From a077b458661e0331c5220bdb6dd73eecc7ca6200 Mon Sep 17 00:00:00 2001 From: Tyler Hallada Date: Fri, 4 Aug 2017 00:50:37 -0400 Subject: [PATCH] Add comments and licences --- LICENSE-3RD-PARTY.txt | 34 ++++++++ LICENSE.txt | 20 +++++ js/field.js | 196 +++++++++++++++++++++++++----------------- 3 files changed, 170 insertions(+), 80 deletions(-) create mode 100644 LICENSE-3RD-PARTY.txt create mode 100644 LICENSE.txt diff --git a/LICENSE-3RD-PARTY.txt b/LICENSE-3RD-PARTY.txt new file mode 100644 index 0000000..41bcaa7 --- /dev/null +++ b/LICENSE-3RD-PARTY.txt @@ -0,0 +1,34 @@ +jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + +Uses the built in easing capabilities added In jQuery 1.1 to offer multiple +easing options + +TERMS OF USE - jQuery Easing + +Open source under the BSD License. + +Copyright © 2008 George McGinley Smith All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. Redistributions in binary form must +reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the +distribution. + +Neither the name of the author nor the names of contributors may be used to +endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..8afb232 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Tyler Hallada + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/js/field.js b/js/field.js index 8b3a7e9..8a1ba5e 100644 --- a/js/field.js +++ b/js/field.js @@ -1,19 +1,19 @@ +/* Sorry, this code is pretty damn ugly. I spend 8 hours 5 days a week refactoring code, I just don't feel like making + * it better right now. Maybe I'll have enough caffiene in my veins and nothing better to do sometime to put this all + * into ES2015 modules or something. + */ +// global vars var renderer; var stage; var screenWidth; var screenHeight; var counter; var totalScreenPixels; -var cycleDuration; var connectionDistance; -var connectionLimit; var pointShiftDistance; -// var colorShiftAmt; -var disconnectedColorShiftAmt; var polygon; var startPoints; var polygonPoints; -var tweeningFns; var lastLoop; var thisLoop; var fps; @@ -21,10 +21,22 @@ var fpsGraphic; var scrollDelta; var pointShiftBiasX; var pointShiftBiasY; -var resolution = 1; -var debug = false; -var fpsEnabled = debug; -var allTweeningFns = [ + +// global non-configurable vars (modifying these might break stuff) +var click = null; +var hover = null; +var lastHover = null; +var clickEnd = false; + +// global configurable vars +var resolution = 1; // scaling for PIXI renderer +var debug = false; // toggles drawing extra indicators for debugging +var fpsEnabled = debug; // toggles the FPS counter +var cycleDuration = 60; // length of a point's "cycle": number of frames it takes for it to travel to its chosen destination +var connectionLimit = 10; // maximum number of lines drawn from one point to others within connection distance +// colorShiftAmt = 80; // disabled for now +var disconnectedColorShiftAmt = 10; // when a point is alone (not connected), shift RGB values by this amount every tick +var allTweeningFns = [ // array of all possible tweening functions, these are defined below linearTweening, easeInSine, easeOutSine, @@ -51,7 +63,8 @@ var allTweeningFns = [ easeOutBack, easeInOutBack ]; -var tweeningSets = { +// sets of tweening functions that I think look good with points randomly choose from them +var tweeningSets = { // numbers refer to indicies into the allTweeningsFns array above linear: [0], meandering: [1, 2, 3, 4, 5, 6, 7, 8, 9], snappy: [10, 11, 12, 13, 14, 15], @@ -59,36 +72,37 @@ var tweeningSets = { elastic: [19, 20, 21], back: [22, 23, 24] }; -var click = null; -var hover = null; -var lastHover = null; -var clickEnd = false; -var clickPullRateStart = 0.01; -var clickMaxDistStart = 50; -var clickPullRateInc = 0.005; -var clickPullRateMax = 0.3; -var clickMaxDistInc = 2; -var clickMaxDistMax = 5000; +var tweeningFns = tweeningSets.meandering; // the actual set of tweening functions points will randomly choose from +// click effect related config vars +var clickPullRateStart = 0.01; // initial value for the ratio of a point's distance from the click position to travel in one cycle +var clickPullRateInc = 0.005; // amount to increase clickPullRate every tick that a click is held +var clickPullRateMax = 0.5; // maximum value of clickPullRate var clickPullRate = clickPullRateStart; +var clickMaxDistStart = 50; // initial value for the effect radius of a click: points this distance from click position will be pulled +var clickMaxDistInc = 2; // amount to increase clickMaxDist every tick that a click is held +var clickMaxDistMax = 5000; // maximum value of clickMaxDist var clickMaxDist = clickMaxDistStart; -var clickPullRateEnd = -0.6; -var clickInertiaStart = -0.7; +var clickInertiaStart = -0.7; // initial value of the ratio of point's origin distance from the click position to be added to point's new target var clickInertia = clickInertiaStart; -var clickInertiaEnd = 0.3; -var clickTweeningFnStart = null; +var clickTweeningFnStart = null; // initial value of the specific tweening function to assign to points in effect radius (null will not change functions) var clickTweeningFn = clickTweeningFnStart; -var clickTweeningFnEnd = 12; -var hoverPushRate = -0.05; -var hoverInertia = 0.8; -var hoverMaxDistStart = 75; -var hoverMaxDistMax = 1000; +var clickColorShiftAmt = disconnectedColorShiftAmt * 3; // amount of RGB color value to shift for each point in effect radius +var clickPullRateEnd = -0.6; // value of clickPullRate during tick after end of click (for "rebound" effect) +var clickInertiaEnd = 0.3; // value of clickInertia during tick after end of click +var clickTweeningFnEnd = 12; // value of clickTweeningFn during tick after end of click (number refers to index into allTweeningsFns) +// hover effect related config vars +var hoverPushRate = -0.05; // ratio of a point's distance from the hover position to travel in one cycle +var hoverInertia = 0.8; // ratio of a point's origin distance from the click position to be added to point's new target +var hoverMaxDistStart = 75; // initial value for the effect radius of a hover: points this distance from hover position will be pushed +var hoverMaxDistMax = 1000; // maximum value of hoverMaxDist var hoverMaxDist = hoverMaxDistStart; -var hoverTweeningFn = 5; +var hoverTweeningFn = 5; // specific tweening function to assign to points in effect radius -function randomInt (min, max) { - // inclusive of min and max - return Math.floor(Math.random() * (max - min + 1)) + min; -} +/* TWEENING FUNCTIONS */ + +// These are modified versions of the jquery easing functions: +// https://github.com/danro/jquery-easing/blob/master/jquery.easing.js +// See license in LICENSE-3RD-PARTY.txt /* eslint-disable no-unused-vars */ function linearTweening (t, b, c, d) { @@ -225,6 +239,13 @@ function easeInOutCirc (t, b, c, d) { } /* eslint-enable no-unused-vars */ +/* UTILITY FUNCTIONS */ + +function randomInt (min, max) { + // inclusive of min and max + return Math.floor(Math.random() * (max - min + 1)) + min; +} + // from: http://stackoverflow.com/a/5624139 // modified to return integer literal function rgbToHex (color) { @@ -301,18 +322,40 @@ function getMousePos (evt, res) { } } -function distancePos (point1, point2) { - var a = point1.x - point2.x; - var b = point1.y - point2.y; - return Math.sqrt(a * a + b * b); -} - function distance (point1, point2) { var a = point1[0] - point2[0]; var b = point1[1] - point2[1]; return Math.sqrt(a * a + b * b); } +function distancePos (point1, point2) { + // TODO: refactor distance and distancePos to the same function + var a = point1.x - point2.x; + var b = point1.y - point2.y; + return Math.sqrt(a * a + b * b); +} + +// eslint-disable-next-line no-unused-vars +function shiftPointCounter (original, maxShiftAmt) { + var shiftAmt = randomInt(maxShiftAmt * -1, 0); + var newCounter = original + shiftAmt; + if (newCounter < 0) { + newCounter = cycleDuration + shiftAmt; + } + return newCounter; +} + +function relativeCounter (counter, targetStart) { + /* Return current progress of point in its cycle. AKA. what count would be if cycleDuration == targetStart */ + var relCounter = counter - targetStart; + if (relCounter < 0) { + return cycleDuration + relCounter; + } + return relCounter; +} + +/* POINT OPERATION FUNCTIONS */ + function getRandomPoints (numPoints, maxX, maxY, tweeningFns) { var i, x, y, color, cycleStart, easingFn; var points = []; @@ -327,16 +370,6 @@ function getRandomPoints (numPoints, maxX, maxY, tweeningFns) { return points; } -// eslint-disable-next-line no-unused-vars -function shiftPointCounter (original, maxShiftAmt) { - var shiftAmt = randomInt(maxShiftAmt * -1, 0); - var newCounter = original + shiftAmt; - if (newCounter < 0) { - newCounter = cycleDuration + shiftAmt; - } - return newCounter; -} - function shiftPoints (points, maxShiftAmt, counter, tweeningFns) { var i, shiftX, shiftY, candidateX, candidateY; for (i = 0; i < points.original.length; i++) { @@ -377,35 +410,42 @@ function shiftPoints (points, maxShiftAmt, counter, tweeningFns) { } function pullPoints (points, clickPos, pullRate, inertia, maxDist, counter, resetPoints, tweeningFn) { - var xDist, yDist, xTraveled, yTraveled; + var targetXDiff, targetYDiff, originXDiff, originYDiff; for (var i = 0; i < points.target.length; i++) { - xDist = clickPos.x - points.target[i][0]; - yDist = clickPos.y - points.target[i][1]; - xTraveled = clickPos.x - points.original[i][0]; - yTraveled = clickPos.y - points.original[i][1]; - if (Math.abs(xDist) <= maxDist && Math.abs(yDist) <= maxDist) { + targetXDiff = clickPos.x - points.target[i][0]; + targetYDiff = clickPos.y - points.target[i][1]; + originXDiff = clickPos.x - points.original[i][0]; + originYDiff = clickPos.y - points.original[i][1]; + if (Math.abs(targetXDiff) <= maxDist && Math.abs(targetYDiff) <= maxDist) { // point is within effect radius if (resetPoints) { // Good for changing directions, reset the points original positions to their current positions points.original[i][0] = points.tweened[i][0]; points.original[i][1] = points.tweened[i][1]; } - points.target[i][0] += Math.round((xDist + (inertia * xTraveled)) * pullRate); - points.target[i][1] += Math.round((yDist + (inertia * yTraveled)) * pullRate); - points.target[i][3] = shiftColor(points.original[i][3], disconnectedColorShiftAmt * 3); + points.target[i][0] += Math.round((targetXDiff + (inertia * originXDiff)) * pullRate); // pull X + points.target[i][1] += Math.round((targetYDiff + (inertia * originYDiff)) * pullRate); // pull Y + // shift the color of each point in effect radius by some configurable amount + points.target[i][3] = shiftColor(points.original[i][3], clickColorShiftAmt); if (tweeningFn !== null) { - // Also twitch the tweening function for all affected points for additional effect + // Also switch the tweening function for all affected points for additional effect + // The tweening function will be re-assigned at the start of the point's next cycle points.target[i][4] = tweeningFn; } } - // TODO: define these magic numbers somewhere // If this point's cycle is near it's end, bump it up some ticks to make the animation smoother - if (relativeCounter(points.target[i][2]) > cycleDuration - 10) { + if (relativeCounter(points.target[i][2]) > Math.roundcycleDuration - 10) { points.target[i][2] = (points.target[i][2] + Math.round(cycleDuration / 2)) % cycleDuration; } } } function redistributeCycles (points, oldCycleDuration, cycleDuration) { + /* Given old and new cycleDuration, re-assign points' cycle starts that expand/compress to fit the new range in a + * way that ensures the current progress of the point in its cycle is around the same percentage (so that the point + * does not jump erratically back or forward in it's current trajectory). + */ + // FIXME: if cycleDuration goes to 1 all points' cycles will be compressed to about the same value, and when + // cycleDuration goes back up, the values will remain the same, making the points appear to dance in sync. var progress; for (var i = 0; i < points.original.length; i++) { progress = points.target[i][2] / oldCycleDuration; @@ -414,13 +454,7 @@ function redistributeCycles (points, oldCycleDuration, cycleDuration) { return points; } -function relativeCounter (counter, targetStart) { - var relCounter = counter - targetStart; - if (relCounter < 0) { - return cycleDuration + relCounter; - } - return relCounter; -} +/* DRAW FUNCTIONS */ function drawPolygon (polygon, points, counter, tweeningFns) { var i, j, easingFn, relativeCount, avgColor, shadedColor, connectionCount, dist, connectivity; @@ -478,6 +512,8 @@ function drawPolygon (polygon, points, counter, tweeningFns) { } } +/* MAIN LOOP */ + function loop () { screenWidth = document.documentElement.clientWidth; screenHeight = document.documentElement.clientHeight; @@ -487,21 +523,24 @@ function loop () { if (click !== null) { if (clickEnd) { + // apply "rebound" effects clickPullRate = clickPullRateEnd; clickInertia = clickInertiaEnd; clickTweeningFn = clickTweeningFnEnd; if (debug) { + // draw debug click effect radius red color when clickEnd == true polygon.lineStyle(1, 0xDC143C, 1); polygon.drawCircle(click.x, click.y, clickMaxDist); } } else { if (debug) { + // draw click effect radius blue when debug is on polygon.lineStyle(1, 0x483D8B, 1); polygon.drawCircle(click.x, click.y, clickMaxDist); } } - // a pointer event is occuring and needs to affect the points + // a pointer event is occuring and needs to affect the points in effect radius pullPoints(polygonPoints, click, clickPullRate, clickInertia, clickMaxDist, counter, clickEnd, clickTweeningFn); // slightly increase effect amount for next loop if click is still occuring @@ -513,6 +552,7 @@ function loop () { } if (clickEnd) { + // done with rebound effect, re-initialize everything to prepare for next click click = null; clickEnd = false; clickMaxDist = clickMaxDistStart; @@ -522,19 +562,23 @@ function loop () { } } else if (hover !== null) { if (lastHover !== null) { + // hover effect radius grows bigger the faster the mouse moves hoverMaxDist += Math.min(Math.round(distancePos(hover, lastHover)), hoverMaxDistMax); } if (debug) { + // draw hover effect radius yellow when debug is on polygon.lineStyle(1, 0xBDB76B, 1); polygon.drawCircle(hover.x, hover.y, hoverMaxDist); } + // a hover event is occuring and needs to affect the points in effect radius pullPoints(polygonPoints, hover, hoverPushRate, hoverInertia, hoverMaxDist, counter, false, hoverTweeningFn); hoverMaxDist = hoverMaxDistStart; lastHover = hover; } + // TODO: it would be cool to fill in triangles // polygon.beginFill(0x00FF00); drawPolygon(polygon, polygonPoints, counter, tweeningFns); // polygon.endFill(); @@ -549,12 +593,9 @@ function loop () { lastLoop = thisLoop; } + // points that have reached the end of their cycles need new targets polygonPoints = shiftPoints(polygonPoints, pointShiftDistance, counter, tweeningFns); - // var mousePosition = renderer.plugins.interaction.mouse.global; - // triangle.x = mousePosition.x; - // triangle.y = mousePosition.y; - // If user scrolled, modify cycleDuration by amount scrolled if (scrollDelta !== 0) { var oldCycleDuration = cycleDuration; @@ -589,14 +630,9 @@ function loopStart () { counter = 0; totalScreenPixels = screenWidth + screenHeight; - cycleDuration = 60; connectionDistance = Math.min(Math.round(totalScreenPixels / 16), 75); - connectionLimit = 10; pointShiftDistance = Math.round(totalScreenPixels / 45); - // colorShiftAmt = 80; - disconnectedColorShiftAmt = 10; polygon = new window.PIXI.Graphics(); - tweeningFns = tweeningSets.meandering; startPoints = getRandomPoints(Math.round(totalScreenPixels / 6), screenWidth, screenHeight, tweeningFns); polygonPoints = { original: startPoints, @@ -712,7 +748,7 @@ window.addEventListener('keydown', function (e) { fpsEnabled = true; lastLoop = new Date(); } - } else if (e.keyCode === 68) { + } else if (e.keyCode === 68) { // d // toggle debug if (debug) { if (fpsEnabled) {