UNPKG

animation-loop

Version:

Easily make and manage animation loops.

337 lines (281 loc) 9.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.version = exports.default = exports.AnimationLoop = void 0; var _from = _interopRequireDefault(require("@babel/runtime/core-js/array/from")); var _set = _interopRequireDefault(require("@babel/runtime/core-js/set")); var _Clock = _interopRequireDefault(require("./Clock")); var _lowclass = _interopRequireDefault(require("lowclass")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var AnimationLoop = (0, _lowclass.default)('AnimationLoop', function (ref) { var Public = ref.Public; var Protected = ref.Protected; var Private = ref.Private; return { constructor: function constructor() { // `Private(this)` gives us access to truly "private" members var self = Private(this); self.animationFnsBefore = new _set.default(); self.animationFns = new _set.default(); self.animationFnsAfter = new _set.default(); self.baseFns = new _set.default(); self.animationFrame = null; Protected(this).needsToRequestEachFrame = true; self.elapsed = 0; self.lastTick = 0; self.interval = null; self.intervals = -1; self.clock = new _Clock.default(); self.started = false; self.paused = false; self.ticking = false; self.forcedTick = false; }, // read-only get elapsed() { return Private(this).elapsed; }, get started() { return Private(this).started; }, get paused() { return Private(this).paused; }, get running() { return Private(this).started && !Private(this).paused; }, get ticking() { return Private(this).ticking; }, get interval() { return Private(this).interval; }, set interval(value) { Private(this).interval = value; }, addAnimationFnBefore: function addAnimationFnBefore(fn) { var self = Private(this); if (typeof fn === 'function') { self.animationFnsBefore.add(fn); } if (this.running) { self._startTicking(); } return fn; }, removeAnimationFnBefore: function removeAnimationFnBefore(fn) { var self = Private(this); self.animationFnsBefore.delete(fn); }, addAnimationFn: function addAnimationFn(fn) { var self = Private(this); if (typeof fn === 'function') { self.animationFns.add(fn); } if (this.running) { self._startTicking(); } return fn; }, removeAnimationFn: function removeAnimationFn(fn) { var self = Private(this); self.animationFns.delete(fn); }, addAnimationFnAfter: function addAnimationFnAfter(fn) { var self = Private(this); if (typeof fn === 'function') { self.animationFnsAfter.add(fn); } if (this.running) { self._startTicking(); } return fn; }, removeAnimationFnAfter: function removeAnimationFnAfter(fn) { var self = Private(this); self.animationFnsAfter.delete(fn); }, hasAnimationFunctions: function hasAnimationFunctions() { var self = Private(this); return self.animationFnsBefore.size || self.animationFns.size || self.animationFnsAfter.size; }, addBaseFn: function addBaseFn(fn) { var self = Private(this); if (typeof fn === 'function') { self.baseFns.add(fn); } return fn; }, removeBaseFn: function removeBaseFn(fn) { var self = Private(this); self.baseFns.delete(fn); }, start: function start() { var self = Private(this); // do nothing if already running if (self.started && !self.paused) { return; } self.started = true; self.paused = false; self.clock.start(); self._startTicking(); }, stop: function stop() { var self = Private(this); // do nothing if already stopped if (!self.started) { return; } self.started = false; self.elapsed = 0; self.clock.stop(); self._stopTicking(); }, pause: function pause() { var self = Private(this); // only pause if already running, otherwise do nothing if (self.started && !self.paused) { self.paused = true; self.clock.stop(); self._stopTicking(); } }, // add an empty function that removes itself on the next tick, forcing a // tick of all other animation base functions. forceTick: function forceTick() { var self = Private(this); if (self.forcedTick) { return; } self.forcedTick = true; this.addAnimationFn(function () { return self.forcedTick = false; }); }, addChildLoop: function addChildLoop() { return new ChildAnimationLoop(this); }, removeChildLoop: function removeChildLoop(child) { Protected(child)._dispose(); }, protected: { _requestFrame: function _requestFrame() { var pro = Protected(this); return requestAnimationFrame(function () { return pro._tick(); }); }, _cancelFrame: function _cancelFrame(frame) { cancelAnimationFrame(frame); }, _dispose: function _dispose() { Public(this).stop(); Private(this)._clearFunctions(); }, _tick: function _tick() { var self = Private(this); var dt = self.clock.getDelta(); self.elapsed += dt; if (!self.interval) { self._callAnimationFunctions(dt); } else { var numIntervals = Math.floor(self.elapsed / self.interval); if (numIntervals > self.intervals) { dt = self.elapsed - self.lastTick; self.intervals = numIntervals; self.lastTick = self.elapsed; self._callAnimationFunctions(dt); } } if (Protected(this).needsToRequestEachFrame) { self.animationFrame = Protected(this)._requestFrame(); } if (!Public(this).hasAnimationFunctions()) { self._stopTicking(); } } }, private: { _clearFunctions: function _clearFunctions() { this.animationFnsBefore.clear(); this.animationFns.clear(); this.animationFnsAfter.clear(); this.baseFns.clear(); }, _startTicking: function _startTicking() { if (!Public(this).hasAnimationFunctions()) { return; } var self = Private(this); if (self.ticking) { return; } self.ticking = true; self.animationFrame = Protected(this)._requestFrame(); }, _stopTicking: function _stopTicking() { var self = Private(this); self.ticking = false; Protected(this)._cancelFrame(self.animationFrame); }, _callAnimationFunctions: function _callAnimationFunctions(dt) { var this$1 = this; for (var i = 0, list = (0, _from.default)(this$1.animationFnsBefore); i < list.length; i += 1) { var fn = list[i]; if (fn(dt, this$1.elapsed) === false) { Public(this$1).removeAnimationFnBefore(fn); } } for (var i$1 = 0, list$1 = (0, _from.default)(this$1.animationFns); i$1 < list$1.length; i$1 += 1) { var fn$1 = list$1[i$1]; if (fn$1(dt, this$1.elapsed) === false) { Public(this$1).removeAnimationFn(fn$1); } } for (var i$2 = 0, list$2 = (0, _from.default)(this$1.animationFnsAfter); i$2 < list$2.length; i$2 += 1) { var fn$2 = list$2[i$2]; if (fn$2(dt, this$1.elapsed) === false) { Public(this$1).removeAnimationFnAfter(fn$2); } } for (var i$3 = 0, list$3 = (0, _from.default)(this$1.baseFns); i$3 < list$3.length; i$3 += 1) { var fn$3 = list$3[i$3]; if (fn$3(dt, this$1.elapsed) === false) { Public(this$1).removeBaseFn(fn$3); } } } } }; }); exports.AnimationLoop = AnimationLoop; var _default = AnimationLoop; // Child loops hook into parent animationFns instead of requestAnimationFrame, // so that there's a single rAF loop at the root AnimationLoop. exports.default = _default; var ChildAnimationLoop = (0, _lowclass.default)('ChildAnimationLoop').extends(AnimationLoop, function (ref) { var Protected = ref.Protected; var Super = ref.Super; return { constructor: function constructor(parentLoop) { Super(this).constructor(); Protected(this).parentLoop = parentLoop; Protected(this).needsToRequestEachFrame = false; }, protected: { _requestFrame: function _requestFrame() { var pro = Protected(this); return this.parentLoop.addAnimationFn(function () { return pro._tick(); }); }, _cancelFrame: function _cancelFrame(frame) { this.parentLoop.removeAnimationFn(frame); }, _dispose: function _dispose() { Super(this)._dispose(); this.parentLoop = null; } } }; }); var version = '1.4.0'; exports.version = version;