Hover, tweeningSets, rebound, scroll time, debug

This commit is contained in:
Tyler Hallada 2017-08-03 00:17:17 -04:00
parent 32f3166f52
commit d32e236e05
2 changed files with 207 additions and 77 deletions

View File

@ -21,25 +21,76 @@ var fpsGraphic;
var scrollDelta; var scrollDelta;
var pointShiftBiasX; var pointShiftBiasX;
var pointShiftBiasY; var pointShiftBiasY;
var resolution = 2; var resolution = 1;
var fpsEnabled = false; var debug = false;
var fpsEnabled = debug;
var allTweeningFns = [
linearTweening,
easeInSine,
easeOutSine,
easeInOutSine,
easeInQuad,
easeOutQuad,
easeInOutQuad,
easeInCubic,
easeOutCubic,
easeInOutCubic,
easeInExpo,
easeOutExpo,
easeInOutExpo,
easeInCirc,
easeOutCirc,
easeInOutCirc,
easeOutBounce,
easeInBounce,
easeInOutBounce,
easeInElastic,
easeOutElastic,
easeInOutElastic,
easeInBack,
easeOutBack,
easeInOutBack
];
var tweeningSets = {
linear: [0],
meandering: [1, 2, 3, 4, 5, 6, 7, 8, 9],
snappy: [10, 11, 12, 13, 14, 15],
bouncy: [16, 17, 18],
elastic: [19, 20, 21],
back: [22, 23, 24]
};
var click = null; var click = null;
var hover = null;
var lastHover = null;
var clickEnd = false; var clickEnd = false;
var clickPullRateStart = 0.02; var clickPullRateStart = 0.01;
var clickMaxDistStart = 100; var clickMaxDistStart = 50;
var clickPullRateInc = 0.0005; var clickPullRateInc = 0.005;
var clickPullRateMax = 0.1; var clickPullRateMax = 0.3;
var clickMaxDistInc = 5; var clickMaxDistInc = 2;
var clickMaxDistMax = 5000; var clickMaxDistMax = 5000;
var clickPullRate = clickPullRateStart; var clickPullRate = clickPullRateStart;
var clickMaxDist = clickMaxDistStart; var clickMaxDist = clickMaxDistStart;
var clickEndRebount = -10; var clickPullRateEnd = -0.6;
var clickInertiaStart = -0.7;
var clickInertia = clickInertiaStart;
var clickInertiaEnd = 0.3;
var clickTweeningFnStart = null;
var clickTweeningFn = clickTweeningFnStart;
var clickTweeningFnEnd = 12;
var hoverPushRate = -0.05;
var hoverInertia = 0.8;
var hoverMaxDistStart = 75;
var hoverMaxDistMax = 1000;
var hoverMaxDist = hoverMaxDistStart;
var hoverTweeningFn = 5;
function randomInt (min, max) { function randomInt (min, max) {
// inclusive of min and max // inclusive of min and max
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
/* eslint-disable no-unused-vars */
function linearTweening (t, b, c, d) { function linearTweening (t, b, c, d) {
// t = current time // t = current time
// b = start value // b = start value
@ -48,7 +99,6 @@ function linearTweening (t, b, c, d) {
return ((c * t) / d) + b; return ((c * t) / d) + b;
} }
/* eslint-disable no-unused-vars */
function easeOutBounce (t, b, c, d) { function easeOutBounce (t, b, c, d) {
if ((t /= d) < (1 / 2.75)) { if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b; return c * (7.5625 * t * t) + b;
@ -61,6 +111,15 @@ function easeOutBounce (t, b, c, d) {
} }
} }
function easeInBounce (t, b, c, d) {
return c - easeOutBounce(d - t, 0, c, d) + b;
}
function easeInOutBounce (t, b, c, d) {
if (t < d / 2) return easeInBounce(t * 2, 0, c, d) * 0.5 + b;
return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
}
function easeInSine (t, b, c, d) { function easeInSine (t, b, c, d) {
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
} }
@ -136,6 +195,22 @@ function easeInOutElastic (t, b, c, d) {
return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b; return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
} }
function easeInBack (t, b, c, d, s) {
if (s === undefined) s = 1.70158;
return c * (t /= d) * t * ((s + 1) * t - s) + b;
}
function easeOutBack (t, b, c, d, s) {
if (s === undefined) s = 1.70158;
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
}
function easeInOutBack (t, b, c, d, s) {
if (s === undefined) s = 1.70158;
if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
}
function easeInCirc (t, b, c, d) { function easeInCirc (t, b, c, d) {
return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
} }
@ -215,13 +290,22 @@ function shiftColor (color, maxShiftAmt) {
} }
/* from: https://stackoverflow.com/a/17130415 */ /* from: https://stackoverflow.com/a/17130415 */
function getMousePos (canvas, evt, res) { function getMousePos (evt, res) {
var canvas = document.getElementsByTagName('canvas')[0];
if (canvas !== undefined) {
var rect = canvas.getBoundingClientRect(); var rect = canvas.getBoundingClientRect();
return { return {
x: Math.round((evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width / res), x: Math.round((evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width / res),
y: Math.round((evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height / res) y: Math.round((evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height / 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) { function distance (point1, point2) {
var a = point1[0] - point2[0]; var a = point1[0] - point2[0];
@ -237,7 +321,7 @@ function getRandomPoints (numPoints, maxX, maxY, tweeningFns) {
y = randomInt(0, maxY - 1); y = randomInt(0, maxY - 1);
cycleStart = randomInt(0, cycleDuration - 1); cycleStart = randomInt(0, cycleDuration - 1);
color = randomColor(); color = randomColor();
easingFn = randomInt(0, tweeningFns.length - 1); easingFn = tweeningFns[Math.floor(Math.random() * tweeningFns.length)];
points[i] = [x, y, cycleStart, color, easingFn]; points[i] = [x, y, cycleStart, color, easingFn];
} }
return points; return points;
@ -280,7 +364,7 @@ function shiftPoints (points, maxShiftAmt, counter, tweeningFns) {
} }
points.target[i][0] = candidateX; points.target[i][0] = candidateX;
points.target[i][1] = candidateY; points.target[i][1] = candidateY;
points.target[i][4] = randomInt(0, tweeningFns.length - 1); points.target[i][4] = tweeningFns[Math.floor(Math.random() * tweeningFns.length)];
// FIXME: buggy, makes points jump around too fast // FIXME: buggy, makes points jump around too fast
// points.target[i][2] = shiftPointCounter(points.original[i][2], maxShiftAmt); // points.target[i][2] = shiftPointCounter(points.original[i][2], maxShiftAmt);
} }
@ -292,15 +376,26 @@ function shiftPoints (points, maxShiftAmt, counter, tweeningFns) {
return points; return points;
} }
function pullPoints (points, clickPos, pullRate, maxDist, counter) { function pullPoints (points, clickPos, pullRate, inertia, maxDist, counter, resetPoints, tweeningFn) {
var xDist, yDist; var xDist, yDist, xTraveled, yTraveled;
for (var i = 0; i < points.target.length; i++) { for (var i = 0; i < points.target.length; i++) {
xDist = clickPos.x - points.target[i][0]; xDist = clickPos.x - points.target[i][0];
yDist = clickPos.y - points.target[i][1]; 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) { if (Math.abs(xDist) <= maxDist && Math.abs(yDist) <= maxDist) {
points.target[i][0] += Math.round(xDist * pullRate); if (resetPoints) {
points.target[i][1] += Math.round(yDist * pullRate); // 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][3] = shiftColor(points.original[i][3], disconnectedColorShiftAmt * 3);
if (tweeningFn !== null) {
// Also twitch the tweening function for all affected points for additional effect
points.target[i][4] = tweeningFn;
}
} }
// TODO: define these magic numbers somewhere // 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 this point's cycle is near it's end, bump it up some ticks to make the animation smoother
@ -310,9 +405,11 @@ function pullPoints (points, clickPos, pullRate, maxDist, counter) {
} }
} }
function redistributeCycles (points) { function redistributeCycles (points, oldCycleDuration, cycleDuration) {
var progress;
for (var i = 0; i < points.original.length; i++) { for (var i = 0; i < points.original.length; i++) {
points.target[i][2] = randomInt(0, cycleDuration - 1); progress = points.target[i][2] / oldCycleDuration;
points.target[i][2] = Math.round(progress * cycleDuration);
} }
return points; return points;
} }
@ -329,7 +426,7 @@ function drawPolygon (polygon, points, counter, tweeningFns) {
var i, j, easingFn, avgColor, shadedColor, connectionCount, dist, connectivity; var i, j, easingFn, avgColor, shadedColor, connectionCount, dist, connectivity;
// calculate vectors // calculate vectors
for (i = 0; i < points.original.length; i++) { for (i = 0; i < points.original.length; i++) {
easingFn = tweeningFns[points.target[i][4]]; easingFn = allTweeningFns[points.target[i][4]];
points.tweened[i][0] = easingFn(relativeCounter(counter, points.target[i][2]), points.original[i][0], points.target[i][0] - points.original[i][0], cycleDuration); points.tweened[i][0] = easingFn(relativeCounter(counter, points.target[i][2]), points.original[i][0], points.target[i][0] - points.original[i][0], cycleDuration);
points.tweened[i][1] = easingFn(relativeCounter(counter, points.target[i][2]), points.original[i][1], points.target[i][1] - points.original[i][1], cycleDuration); points.tweened[i][1] = easingFn(relativeCounter(counter, points.target[i][2]), points.original[i][1], points.target[i][1] - points.original[i][1], cycleDuration);
} }
@ -377,10 +474,22 @@ function loop () {
if (click !== null) { if (click !== null) {
if (clickEnd) { if (clickEnd) {
clickPullRate *= clickEndRebount; clickPullRate = clickPullRateEnd;
clickInertia = clickInertiaEnd;
clickTweeningFn = clickTweeningFnEnd;
if (debug) {
polygon.lineStyle(1, 0xDC143C, 1);
polygon.drawCircle(click.x, click.y, clickMaxDist);
} }
} else {
if (debug) {
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
pullPoints(polygonPoints, click, clickPullRate, clickMaxDist, counter); pullPoints(polygonPoints, click, clickPullRate, clickInertia, clickMaxDist, counter, clickEnd, clickTweeningFn);
// slightly increase effect amount for next loop if click is still occuring // slightly increase effect amount for next loop if click is still occuring
if (clickMaxDist <= clickMaxDistMax) { if (clickMaxDist <= clickMaxDistMax) {
@ -395,10 +504,27 @@ function loop () {
clickEnd = false; clickEnd = false;
clickMaxDist = clickMaxDistStart; clickMaxDist = clickMaxDistStart;
clickPullRate = clickPullRateStart; clickPullRate = clickPullRateStart;
clickInertia = clickInertiaStart;
clickTweeningFn = clickTweeningFnStart;
} }
} else if (hover !== null) {
if (lastHover !== null) {
hoverMaxDist += Math.min(Math.round(distancePos(hover, lastHover)), hoverMaxDistMax);
}
if (debug) {
polygon.lineStyle(1, 0xBDB76B, 1);
polygon.drawCircle(hover.x, hover.y, hoverMaxDist);
} }
pullPoints(polygonPoints, hover, hoverPushRate, hoverInertia, hoverMaxDist, counter, false, hoverTweeningFn);
hoverMaxDist = hoverMaxDistStart;
lastHover = hover;
}
// polygon.beginFill(0x00FF00);
drawPolygon(polygon, polygonPoints, counter, tweeningFns); drawPolygon(polygon, polygonPoints, counter, tweeningFns);
// polygon.endFill();
counter += 1; counter += 1;
counter = counter % cycleDuration; counter = counter % cycleDuration;
@ -418,12 +544,13 @@ function loop () {
// If user scrolled, modify cycleDuration by amount scrolled // If user scrolled, modify cycleDuration by amount scrolled
if (scrollDelta !== 0) { if (scrollDelta !== 0) {
cycleDuration = cycleDuration + scrollDelta; var oldCycleDuration = cycleDuration;
cycleDuration = Math.round(cycleDuration + scrollDelta);
if (cycleDuration < 1) { if (cycleDuration < 1) {
cycleDuration = 1; cycleDuration = 1;
} }
scrollDelta = 0; scrollDelta = 0;
polygonPoints = redistributeCycles(polygonPoints); polygonPoints = redistributeCycles(polygonPoints, oldCycleDuration, cycleDuration);
} }
// Tell the `renderer` to `render` the `stage` // Tell the `renderer` to `render` the `stage`
@ -456,28 +583,7 @@ function loopStart () {
// colorShiftAmt = 80; // colorShiftAmt = 80;
disconnectedColorShiftAmt = 10; disconnectedColorShiftAmt = 10;
polygon = new window.PIXI.Graphics(); polygon = new window.PIXI.Graphics();
tweeningFns = [ tweeningFns = tweeningSets.meandering;
linearTweening,
easeInSine,
easeOutSine,
easeInOutSine,
easeInQuad,
easeOutQuad,
easeInOutQuad,
easeInCubic,
easeOutCubic,
easeInOutCubic
// easeOutBounce,
// easeInElastic,
// easeOutElastic,
// easeInOutElastic,
// easeInExpo,
// easeOutExpo,
// easeInOutExpo,
// easeInCirc,
// easeOutCirc,
// easeInOutCirc
];
startPoints = getRandomPoints(Math.round(totalScreenPixels / 6), screenWidth, screenHeight, tweeningFns); startPoints = getRandomPoints(Math.round(totalScreenPixels / 6), screenWidth, screenHeight, tweeningFns);
polygonPoints = { polygonPoints = {
original: startPoints, original: startPoints,
@ -501,43 +607,22 @@ function loopStart () {
window.requestAnimationFrame(loop); window.requestAnimationFrame(loop);
} }
function updateClickPos (event) {
var canvas = document.getElementsByTagName('canvas')[0];
click = getMousePos(canvas, event, resolution);
}
window.onload = loopStart; window.onload = loopStart;
window.addEventListener('mousewheel', function (e) { /* MOUSE AND TOUCH EVENTS */
// scrollDelta = scrollDelta + ((e.deltaY / 100) * 3);
// FIXME: buggy :( // FIXME: buggy :(
}); window.addEventListener('mousewheel', function (e) {
scrollDelta = scrollDelta + ((e.deltaY / 100) * 3);
window.addEventListener('mousedown', function (e) {
updateClickPos(e);
});
window.addEventListener('mousemove', function (e) {
if (click !== null) {
updateClickPos(e);
}
});
window.addEventListener('mouseup', function (e) {
clickEnd = true;
});
window.addEventListener('mouseleave', function (e) {
clickEnd = true;
}); });
window.addEventListener('touchstart', function (e) { window.addEventListener('touchstart', function (e) {
updateClickPos(e.changedTouches[0]); click = getMousePos(e.changedTouches[0], resolution);
}); });
window.addEventListener('touchmove', function (e) { window.addEventListener('touchmove', function (e) {
if (click !== null) { if (click !== null) {
updateClickPos(e.changedTouches[0]); click = getMousePos(e.changedTouches[0], resolution);
} }
}); });
@ -549,6 +634,32 @@ window.addEventListener('touchcancel', function (e) {
clickEnd = true; clickEnd = true;
}); });
window.addEventListener('mousedown', function (e) {
click = getMousePos(e, resolution);
});
window.addEventListener('mousemove', function (e) {
var pos = getMousePos(e, resolution);
if (click !== null) {
click = pos;
}
hover = pos;
});
window.addEventListener('mouseup', function (e) {
clickEnd = true;
hover = null;
lastHover = null;
});
window.addEventListener('mouseleave', function (e) {
clickEnd = true;
hover = null;
lastHover = null;
});
/* KEYBOARD EVENTS */
window.addEventListener('keydown', function (e) { window.addEventListener('keydown', function (e) {
if (e.keyCode === 37) { // left if (e.keyCode === 37) { // left
pointShiftBiasX = -1; pointShiftBiasX = -1;
@ -558,6 +669,18 @@ window.addEventListener('keydown', function (e) {
pointShiftBiasX = 1; pointShiftBiasX = 1;
} else if (e.keyCode === 40) { // down } else if (e.keyCode === 40) { // down
pointShiftBiasY = 1; pointShiftBiasY = 1;
} else if (e.keyCode === 49) { // 1
tweeningFns = tweeningSets.linear;
} else if (e.keyCode === 50) { // 2
tweeningFns = tweeningSets.meandering;
} else if (e.keyCode === 51) { // 3
tweeningFns = tweeningSets.snappy;
} else if (e.keyCode === 52) { // 4
tweeningFns = tweeningSets.bouncy;
} else if (e.keyCode === 53) { // 5
tweeningFns = tweeningSets.elastic;
} else if (e.keyCode === 54) { // 6
tweeningFns = tweeningSets.back;
} else if (e.keyCode === 70) { // f } else if (e.keyCode === 70) { // f
// toggle fpsCounter // toggle fpsCounter
if (fpsEnabled) { if (fpsEnabled) {

View File

@ -14,3 +14,10 @@ Click events:
* Continue with drawPolygon * Continue with drawPolygon
Make a better points data structure with x and y keys. Make a better points data structure with x and y keys.
For debugging, display a line of the intended path for each point.
* Run the whole tween function in one tick, drawing a single pixel along
If lines make a connected polygon, shade the inside of it with the average color
of all vertices composing the polygon. The more distant the points (and the
larger the polygon) the more dark the color is shaded.