summaryrefslogtreecommitdiffstats
path: root/src/animation/Animator.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/animation/Animator.js')
-rw-r--r--src/animation/Animator.js85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/animation/Animator.js b/src/animation/Animator.js
new file mode 100644
index 0000000..fdb2326
--- /dev/null
+++ b/src/animation/Animator.js
@@ -0,0 +1,85 @@
+import Queue from './Queue.js'
+
+const Animator = {
+ nextDraw: null,
+ frames: new Queue(),
+ timeouts: new Queue(),
+ timer: window.performance || window.Date,
+ transforms: [],
+
+ frame (fn) {
+ // Store the node
+ var node = Animator.frames.push({ run: fn })
+
+ // Request an animation frame if we don't have one
+ if (Animator.nextDraw === null) {
+ Animator.nextDraw = window.requestAnimationFrame(Animator._draw)
+ }
+
+ // Return the node so we can remove it easily
+ return node
+ },
+
+ transform_frame (fn, id) {
+ Animator.transforms[id] = fn
+ },
+
+ timeout (fn, delay) {
+ delay = delay || 0
+
+ // Work out when the event should fire
+ var time = Animator.timer.now() + delay
+
+ // Add the timeout to the end of the queue
+ var node = Animator.timeouts.push({ run: fn, time: time })
+
+ // Request another animation frame if we need one
+ if (Animator.nextDraw === null) {
+ Animator.nextDraw = window.requestAnimationFrame(Animator._draw)
+ }
+
+ return node
+ },
+
+ cancelFrame (node) {
+ Animator.frames.remove(node)
+ },
+
+ clearTimeout (node) {
+ Animator.timeouts.remove(node)
+ },
+
+ _draw (now) {
+ // Run all the timeouts we can run, if they are not ready yet, add them
+ // to the end of the queue immediately! (bad timeouts!!! [sarcasm])
+ var nextTimeout = null
+ var lastTimeout = Animator.timeouts.last()
+ while ((nextTimeout = Animator.timeouts.shift())) {
+ // Run the timeout if its time, or push it to the end
+ if (now >= nextTimeout.time) {
+ nextTimeout.run()
+ } else {
+ Animator.timeouts.push(nextTimeout)
+ }
+
+ // If we hit the last item, we should stop shifting out more items
+ if (nextTimeout === lastTimeout) break
+ }
+
+ // Run all of the animation frames
+ var nextFrame = null
+ var lastFrame = Animator.frames.last()
+ while ((nextFrame !== lastFrame) && (nextFrame = Animator.frames.shift())) {
+ nextFrame.run()
+ }
+
+ Animator.transforms.forEach(function (el) { el() })
+
+ // If we have remaining timeouts or frames, draw until we don't anymore
+ Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first()
+ ? window.requestAnimationFrame(Animator._draw)
+ : null
+ }
+}
+
+export default Animator