(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.tween = factory()); }(this, (function () { 'use strict'; var version = '18.4.2'; /** * tween.js - licensed under the mit license * https://github.com/tweenjs/tween.js * ---------------------------------------------- * * see https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. * thank you all, you're awesome! */ var _group = function () { this._tweens = {}; this._tweensaddedduringupdate = {}; }; _group.prototype = { getall: function () { return object.keys(this._tweens).map(function (tweenid) { return this._tweens[tweenid]; }.bind(this)); }, removeall: function () { this._tweens = {}; }, add: function (tween) { this._tweens[tween.getid()] = tween; this._tweensaddedduringupdate[tween.getid()] = tween; }, remove: function (tween) { delete this._tweens[tween.getid()]; delete this._tweensaddedduringupdate[tween.getid()]; }, update: function (time, preserve) { var tweenids = object.keys(this._tweens); if (tweenids.length === 0) { return false; } time = time !== undefined ? time : tween.now(); // tweens are updated in "batches". if you add a new tween during an // update, then the new tween will be updated in the next batch. // if you remove a tween during an update, it may or may not be updated. // however, if the removed tween was added during the current batch, // then it will not be updated. while (tweenids.length > 0) { this._tweensaddedduringupdate = {}; for (var i = 0; i < tweenids.length; i++) { var tween = this._tweens[tweenids[i]]; if (tween && tween.update(time) === false) { tween._isplaying = false; if (!preserve) { delete this._tweens[tweenids[i]]; } } } tweenids = object.keys(this._tweensaddedduringupdate); } return true; } }; var tween = new _group(); tween.group = _group; tween._nextid = 0; tween.nextid = function () { return tween._nextid++; }; // include a performance.now polyfill. // in node.js, use process.hrtime. if (typeof (self) === 'undefined' && typeof (process) !== 'undefined' && process.hrtime) { tween.now = function () { var time = process.hrtime(); // convert [seconds, nanoseconds] to milliseconds. return time[0] * 1000 + time[1] / 1000000; }; } // in a browser, use self.performance.now if it is available. else if (typeof (self) !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) { // this must be bound, because directly assigning this function // leads to an invocation exception in chrome. tween.now = self.performance.now.bind(self.performance); } // use date.now if it is available. else if (date.now !== undefined) { tween.now = date.now; } // otherwise, use 'new date().gettime()'. else { tween.now = function () { return new date().gettime(); }; } tween.tween = function (object, group) { this._ispaused = false; this._pausestart = null; this._object = object; this._valuesstart = {}; this._valuesend = {}; this._valuesstartrepeat = {}; this._duration = 1000; this._repeat = 0; this._repeatdelaytime = undefined; this._yoyo = false; this._isplaying = false; this._reversed = false; this._delaytime = 0; this._starttime = null; this._easingfunction = tween.easing.linear.none; this._interpolationfunction = tween.interpolation.linear; this._chainedtweens = []; this._onstartcallback = null; this._onstartcallbackfired = false; this._onupdatecallback = null; this._onrepeatcallback = null; this._oncompletecallback = null; this._onstopcallback = null; this._group = group || tween; this._id = tween.nextid(); }; tween.tween.prototype = { getid: function () { return this._id; }, isplaying: function () { return this._isplaying; }, ispaused: function () { return this._ispaused; }, to: function (properties, duration) { this._valuesend = object.create(properties); if (duration !== undefined) { this._duration = duration; } return this; }, duration: function duration(d) { this._duration = d; return this; }, start: function (time) { this._group.add(this); this._isplaying = true; this._ispaused = false; this._onstartcallbackfired = false; this._starttime = time !== undefined ? typeof time === 'string' ? tween.now() + parsefloat(time) : time : tween.now(); this._starttime += this._delaytime; for (var property in this._valuesend) { // check if an array was provided as property value if (this._valuesend[property] instanceof array) { if (this._valuesend[property].length === 0) { continue; } // create a local copy of the array with the start value at the front this._valuesend[property] = [this._object[property]].concat(this._valuesend[property]); } // if `to()` specifies a property that doesn't exist in the source object, // we should not set that property in the object if (this._object[property] === undefined) { continue; } // save the starting value, but only once. if (typeof(this._valuesstart[property]) === 'undefined') { this._valuesstart[property] = this._object[property]; } if ((this._valuesstart[property] instanceof array) === false) { this._valuesstart[property] *= 1.0; // ensures we're using numbers, not strings } this._valuesstartrepeat[property] = this._valuesstart[property] || 0; } return this; }, stop: function () { if (!this._isplaying) { return this; } this._group.remove(this); this._isplaying = false; this._ispaused = false; if (this._onstopcallback !== null) { this._onstopcallback(this._object); } this.stopchainedtweens(); return this; }, end: function () { this.update(infinity); return this; }, pause: function(time) { if (this._ispaused || !this._isplaying) { return this; } this._ispaused = true; this._pausestart = time === undefined ? tween.now() : time; this._group.remove(this); return this; }, resume: function(time) { if (!this._ispaused || !this._isplaying) { return this; } this._ispaused = false; this._starttime += (time === undefined ? tween.now() : time) - this._pausestart; this._pausestart = 0; this._group.add(this); return this; }, stopchainedtweens: function () { for (var i = 0, numchainedtweens = this._chainedtweens.length; i < numchainedtweens; i++) { this._chainedtweens[i].stop(); } }, group: function (group) { this._group = group; return this; }, delay: function (amount) { this._delaytime = amount; return this; }, repeat: function (times) { this._repeat = times; return this; }, repeatdelay: function (amount) { this._repeatdelaytime = amount; return this; }, yoyo: function (yoyo) { this._yoyo = yoyo; return this; }, easing: function (easingfunction) { this._easingfunction = easingfunction; return this; }, interpolation: function (interpolationfunction) { this._interpolationfunction = interpolationfunction; return this; }, chain: function () { this._chainedtweens = arguments; return this; }, onstart: function (callback) { this._onstartcallback = callback; return this; }, onupdate: function (callback) { this._onupdatecallback = callback; return this; }, onrepeat: function onrepeat(callback) { this._onrepeatcallback = callback; return this; }, oncomplete: function (callback) { this._oncompletecallback = callback; return this; }, onstop: function (callback) { this._onstopcallback = callback; return this; }, update: function (time) { var property; var elapsed; var value; if (time < this._starttime) { return true; } if (this._onstartcallbackfired === false) { if (this._onstartcallback !== null) { this._onstartcallback(this._object); } this._onstartcallbackfired = true; } elapsed = (time - this._starttime) / this._duration; elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; value = this._easingfunction(elapsed); for (property in this._valuesend) { // don't update properties that do not exist in the source object if (this._valuesstart[property] === undefined) { continue; } var start = this._valuesstart[property] || 0; var end = this._valuesend[property]; if (end instanceof array) { this._object[property] = this._interpolationfunction(end, value); } else { // parses relative end values with start as base (e.g.: +10, -3) if (typeof (end) === 'string') { if (end.charat(0) === '+' || end.charat(0) === '-') { end = start + parsefloat(end); } else { end = parsefloat(end); } } // protect against non numeric properties. if (typeof (end) === 'number') { this._object[property] = start + (end - start) * value; } } } if (this._onupdatecallback !== null) { this._onupdatecallback(this._object, elapsed); } if (elapsed === 1) { if (this._repeat > 0) { if (isfinite(this._repeat)) { this._repeat--; } // reassign starting values, restart by making starttime = now for (property in this._valuesstartrepeat) { if (typeof (this._valuesend[property]) === 'string') { this._valuesstartrepeat[property] = this._valuesstartrepeat[property] + parsefloat(this._valuesend[property]); } if (this._yoyo) { var tmp = this._valuesstartrepeat[property]; this._valuesstartrepeat[property] = this._valuesend[property]; this._valuesend[property] = tmp; } this._valuesstart[property] = this._valuesstartrepeat[property]; } if (this._yoyo) { this._reversed = !this._reversed; } if (this._repeatdelaytime !== undefined) { this._starttime = time + this._repeatdelaytime; } else { this._starttime = time + this._delaytime; } if (this._onrepeatcallback !== null) { this._onrepeatcallback(this._object); } return true; } else { if (this._oncompletecallback !== null) { this._oncompletecallback(this._object); } for (var i = 0, numchainedtweens = this._chainedtweens.length; i < numchainedtweens; i++) { // make the chained tweens start exactly at the time they should, // even if the `update()` method was called way past the duration of the tween this._chainedtweens[i].start(this._starttime + this._duration); } return false; } } return true; } }; tween.easing = { linear: { none: function (k) { return k; } }, quadratic: { in: function (k) { return k * k; }, out: function (k) { return k * (2 - k); }, inout: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k; } return - 0.5 * (--k * (k - 2) - 1); } }, cubic: { in: function (k) { return k * k * k; }, out: function (k) { return --k * k * k + 1; }, inout: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k; } return 0.5 * ((k -= 2) * k * k + 2); } }, quartic: { in: function (k) { return k * k * k * k; }, out: function (k) { return 1 - (--k * k * k * k); }, inout: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k; } return - 0.5 * ((k -= 2) * k * k * k - 2); } }, quintic: { in: function (k) { return k * k * k * k * k; }, out: function (k) { return --k * k * k * k * k + 1; }, inout: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k * k; } return 0.5 * ((k -= 2) * k * k * k * k + 2); } }, sinusoidal: { in: function (k) { return 1 - math.cos(k * math.pi / 2); }, out: function (k) { return math.sin(k * math.pi / 2); }, inout: function (k) { return 0.5 * (1 - math.cos(math.pi * k)); } }, exponential: { in: function (k) { return k === 0 ? 0 : math.pow(1024, k - 1); }, out: function (k) { return k === 1 ? 1 : 1 - math.pow(2, - 10 * k); }, inout: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } if ((k *= 2) < 1) { return 0.5 * math.pow(1024, k - 1); } return 0.5 * (- math.pow(2, - 10 * (k - 1)) + 2); } }, circular: { in: function (k) { return 1 - math.sqrt(1 - k * k); }, out: function (k) { return math.sqrt(1 - (--k * k)); }, inout: function (k) { if ((k *= 2) < 1) { return - 0.5 * (math.sqrt(1 - k * k) - 1); } return 0.5 * (math.sqrt(1 - (k -= 2) * k) + 1); } }, elastic: { in: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } return -math.pow(2, 10 * (k - 1)) * math.sin((k - 1.1) * 5 * math.pi); }, out: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } return math.pow(2, -10 * k) * math.sin((k - 0.1) * 5 * math.pi) + 1; }, inout: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } k *= 2; if (k < 1) { return -0.5 * math.pow(2, 10 * (k - 1)) * math.sin((k - 1.1) * 5 * math.pi); } return 0.5 * math.pow(2, -10 * (k - 1)) * math.sin((k - 1.1) * 5 * math.pi) + 1; } }, back: { in: function (k) { var s = 1.70158; return k * k * ((s + 1) * k - s); }, out: function (k) { var s = 1.70158; return --k * k * ((s + 1) * k + s) + 1; }, inout: function (k) { var s = 1.70158 * 1.525; if ((k *= 2) < 1) { return 0.5 * (k * k * ((s + 1) * k - s)); } return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); } }, bounce: { in: function (k) { return 1 - tween.easing.bounce.out(1 - k); }, out: function (k) { if (k < (1 / 2.75)) { return 7.5625 * k * k; } else if (k < (2 / 2.75)) { return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; } else if (k < (2.5 / 2.75)) { return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } }, inout: function (k) { if (k < 0.5) { return tween.easing.bounce.in(k * 2) * 0.5; } return tween.easing.bounce.out(k * 2 - 1) * 0.5 + 0.5; } } }; tween.interpolation = { linear: function (v, k) { var m = v.length - 1; var f = m * k; var i = math.floor(f); var fn = tween.interpolation.utils.linear; if (k < 0) { return fn(v[0], v[1], f); } if (k > 1) { return fn(v[m], v[m - 1], m - f); } return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); }, bezier: function (v, k) { var b = 0; var n = v.length - 1; var pw = math.pow; var bn = tween.interpolation.utils.bernstein; for (var i = 0; i <= n; i++) { b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); } return b; }, catmullrom: function (v, k) { var m = v.length - 1; var f = m * k; var i = math.floor(f); var fn = tween.interpolation.utils.catmullrom; if (v[0] === v[m]) { if (k < 0) { i = math.floor(f = m * (1 + k)); } return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); } else { if (k < 0) { return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); } if (k > 1) { return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); } return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); } }, utils: { linear: function (p0, p1, t) { return (p1 - p0) * t + p0; }, bernstein: function (n, i) { var fc = tween.interpolation.utils.factorial; return fc(n) / fc(i) / fc(n - i); }, factorial: (function () { var a = [1]; return function (n) { var s = 1; if (a[n]) { return a[n]; } for (var i = n; i > 1; i--) { s *= i; } a[n] = s; return s; }; })(), catmullrom: function (p0, p1, p2, p3, t) { var v0 = (p2 - p0) * 0.5; var v1 = (p3 - p1) * 0.5; var t2 = t * t; var t3 = t * t2; return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; } } }; tween.version = version; return tween; })));