Skip to content

Instantly share code, notes, and snippets.

@macu
Last active December 12, 2015 03:09
Show Gist options
  • Select an option

  • Save macu/4705005 to your computer and use it in GitHub Desktop.

Select an option

Save macu/4705005 to your computer and use it in GitHub Desktop.
Basic utility to simplify html5 animation. Exports the `start` function.
define ->
rAF = window["requestAnimationFrame"]
cAF = window["cancelAnimationFrame"]
# based on polyfill by Erik Möller,
# with fixes from Paul Irish and Tino Zijdel.
# https://gist.github.com/1579671
if !rAF or !cAF then do ->
for v in ['ms', 'moz', 'webkit', 'o']
rAF ?= window["#{v}RequestAnimationFrame"]
cAF ?= window["#{v}CancelAnimationFrame"] or
window["#{v}CancelRequestAnimationFrame"]
return
if !rAF or !cAF then do ->
# if either is undefined, use manual timeout at ~62fps.
# keep a queue of callbacks and call them all on timeout,
# rather than setting a separate timeout for each.
# this allows multiple independent animations on each frame.
cbQueue = {}
currAnim = null
lastTime = 0
dAF = (currTime) ->
# draw: call all queued callbacks for the current frame
queue = cbQueue
cbQueue = {}
currAnim = null
cb?(currTime) for cb of queue
return
rAF = (cb) ->
# request: add callback to queue for next frame
cbQueue[cb] = true
return cb if currAnim
currTime = Date.now?() or (new Date).getTime()
waitTime = Math.max(0, 16 - (currTime - lastTime)) # ~62fps
lastTime = currTime + waitTime
currAnim = window.setTimeout((-> dAF(lastTime)), waitTime)
return cb
cAF = (an) ->
# cancel: remove callback from queue for next frame
cbCount = 0
for cb of cbQueue
if cb == an then delete cbQueue[cb]
else if cb then cbCount++
if cbCount == 0
window.clearTimeout currAnim
currAnim = null
return
return
# the old method staggers independent animations.
# rAF = (cb) ->
# currTime = (new Date).getTime()
# waitTime = Math.max(0, 16 - (currTime - lastTime)) # ~60 hz
# lastTime = currTime + waitTime
# window.setTimeout((-> cb(lastTime)), waitTime)
# cAF = (an) ->
# window.clearTimeout(an)
##################################################
# EXPORTS
start: (fn, cb, el) ->
# start returns a controller for the animation.
# fn is called on the next animation frame.
# fn receives the elapsed time since anim start, and the controls.
# fn should perform drawing, and return true for another frame.
# call controls.stop() to end the animation and invoke cb.
# call controls.cancel() to end without invoking cb.
initTime = null
currAnim = null
done = false
controls = {
busy: -> !done
stop: -> if !done then @cancel(); if cb then cb()
cancel: -> done = true; cAF currAnim
}
next = -> currAnim = rAF step, el
step = (currTime) -> if !done
initTime ?= currTime
if fn(currTime - initTime, controls) then next()
else controls.stop()
next()
return controls
define(function(){var f,g;g=window.requestAnimationFrame;f=window.cancelAnimationFrame;g&&f||function(){var e,b,h,c;c=["ms","moz","webkit","o"];b=0;for(h=c.length;b<h;b++)e=c[b],null==g&&(g=window[""+e+"RequestAnimationFrame"]),null==f&&(f=window[""+e+"CancelAnimationFrame"]||window[""+e+"CancelRequestAnimationFrame"])}();g&&f||function(){var e,b,h,c;e={};b=null;c=0;h=function(c){var a,d;d=e;e={};b=null;for(a in d)"function"===typeof a&&a(c)};g=function(k){var a,d;e[k]=!0;if(b)return k;a=("function"===
typeof Date.now?Date.now():void 0)||(new Date).getTime();d=Math.max(0,16-(a-c));c=a+d;b=window.setTimeout(function(){return h(c)},d);return k};f=function(c){var a,d;d=0;for(a in e)a===c?delete e[a]:a&&d++;0===d&&(window.clearTimeout(b),b=null)}}();return{start:function(e,b,h){var c,k,a,d,l,m;k=d=null;a=!1;c={a:function(){return!a},stop:function(){if(!a&&(this.cancel(),b))return b()},cancel:function(){a=!0;return f(k)}};l=function(){return k=g(m,h)};m=function(b){if(!a)return null==d&&(d=b),e(b-d,
c)?l():c.stop()};l();return c}}});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment