diff options
Diffstat (limited to 'client/vendor/oktransition.js')
| -rw-r--r-- | client/vendor/oktransition.js | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/client/vendor/oktransition.js b/client/vendor/oktransition.js new file mode 100644 index 0000000..816ffb0 --- /dev/null +++ b/client/vendor/oktransition.js @@ -0,0 +1,182 @@ +/* + oktransition.add({ + obj: el.style, + units: "px", + from: { left: 0 }, + to: { left: 100 }, + duration: 1000, + easing: oktransition.easing.circ_out, + update: function(obj){ + console.log(obj.left) + } + finished: function(){ + console.log("done") + } + }) +*/ + +const oktransition = {}; +let transitions = []; + +let last_t = 0; +let id = 0; + +const lerp = (n, a, b) => (b - a) * n + a; + +oktransition.speed = 1; +oktransition.add = (transition) => { + transition.id = id++; + transition.obj = transition.obj || {}; + if (transition.easing) { + if (typeof transition.easing === "string") { + transition.easing = oktransition.easing[transition.easing]; + } + } else { + transition.easing = oktransition.easing.linear; + } + if (!("from" in transition) && !("to" in transition)) { + transition.keys = []; + } else if (!("from" in transition)) { + transition.from = {}; + transition.keys = Object.keys(transition.to); + transition.keys.forEach(function (prop) { + transition.from[prop] = parseFloat(transition.obj[prop]); + }); + } else { + transition.keys = Object.keys(transition.from); + } + transition.delay = transition.delay || 0; + transition.start = last_t + transition.delay; + transition.done = false; + transition.after = transition.after || []; + transition.then = (fn) => { + transition.after.push(fn); + return transition; + }; + transition.tick = 0; + transition.skip = transition.skip || 1; + transition.dt = 0; + transition.cancel = () => + (transitions = transitions.filter((item) => item !== transition)); + transitions.push(transition); + return transition; +}; +oktransition.update = (t) => { + let done = false; + requestAnimationFrame(oktransition.update); + last_t = t * oktransition.speed; + if (transitions.length === 0) return; + transitions.forEach((transition, i) => { + const dt = Math.min(1.0, (t - transition.start) / transition.duration); + transition.tick++; + if ( + dt < 0 || + (dt < 1 && transition.tick % transition.skip != 0) || + transition.done + ) + return; + const ddt = transition.easing(dt); + transition.dt = ddt; + transition.keys.forEach((prop) => { + let val = lerp(ddt, transition.from[prop], transition.to[prop]); + if (transition.round) val = Math.round(val); + if (transition.units) val = Math.round(val) + transition.units; + transition.obj[prop] = val; + }); + if (transition.update) { + transition.update(transition.obj, dt); + } + if (dt === 1) { + if (transition.finished) { + transition.finished(transition); + } + if (transition.after.length) { + const twn = transition.after.shift(); + twn.obj = twn.obj || transition.obj; + twn.after = transition.after; + oktransition.add(twn); + } + if (transition.loop) { + transition.start = t + transition.delay; + } else { + done = true; + transition.done = true; + } + } + }); + if (done) { + transitions = transitions.filter((transition) => !transition.done); + } +}; + +requestAnimationFrame(oktransition.update); + +oktransition.easing = { + linear: (t) => { + return t; + }, + circ_out: (t) => { + return Math.sqrt(1 - (t = t - 1) * t); + }, + circ_in: (t) => { + return -(Math.sqrt(1 - t * t) - 1); + }, + circ_in_out: (t) => { + return (t *= 2) < 1 + ? -0.5 * (Math.sqrt(1 - t * t) - 1) + : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); + }, + quad_in: (n) => { + return Math.pow(n, 2); + }, + quad_out: (n) => { + return n * (n - 2) * -1; + }, + quad_in_out: (n) => { + n = n * 2; + if (n < 1) { + return Math.pow(n, 2) / 2; + } + return (-1 * (--n * (n - 2) - 1)) / 2; + }, + cubic_bezier: (mX1, mY1, mX2, mY2) => { + function A(aA1, aA2) { + return 1.0 - 3.0 * aA2 + 3.0 * aA1; + } + function B(aA1, aA2) { + return 3.0 * aA2 - 6.0 * aA1; + } + function C(aA1) { + return 3.0 * aA1; + } + + // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. + function CalcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; + } + + // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. + function GetSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + } + + function GetTForX(aX) { + // Newton raphson iteration + let aGuessT = aX; + for (let i = 0; i < 10; ++i) { + const currentSlope = GetSlope(aGuessT, mX1, mX2); + if (currentSlope == 0.0) return aGuessT; + const currentX = CalcBezier(aGuessT, mX1, mX2) - aX; + aGuessT -= currentX / currentSlope; + } + return aGuessT; + } + + return function (aX) { + if (mX1 == mY1 && mX2 == mY2) return aX; // linear + return CalcBezier(aX, mY1, mY2); + }; + }, +}; + +export default oktransition; |
