I often find myself writing a lot of the same code from project to project. One of those pieces of code is around using requestAnimationFrame and cancelRequestAnimationFrame. I wrote a quick and dirty animation object that allows me to register all of my rendering functions, start the animation and cancel it. Here’s an example of how to use this object:
function render () { // Do your rendering work here } Animation.add(render); Animation.start();
It can also be used to add several animations before and even after Animation has started, you can add new rendering routines on the fly. This is useful in a number of instances where objects have their own render routines and you want to add rendering routines at different times.
I put in a few workarounds. The typical hack to allow setTimeout/cancelTimeout fallbacks are in there. There is also a work around to deal with the missing mozCancelRequestAnimationFrame and the fact that mozRequestAnimationFrame doesn’t return an integer per spec.
So here’s the code for the Animation object:
/*! * jsSimple v0.0.1 * www.jssimple.com * * Copyright (c) Tobin Titus * Available under the BSD and MIT licenses: www.jssimple.com/license/ */ var Animation = (function() { "use strict"; var interval, moz, renderers = []; // PRIVATE function __mozFix (val) { /* Mozilla fails to return interger per specification */ if (!val) { moz = true; val = Math.ceil(Math.random() * 10000); } return val; } function __renderAll() { var r, length; // execute all renderers length = renderers.length; for (r = 0; r < length; ++r) { renderers[r](); } if (interval) { interval = __mozFix(window.requestAnimationFrame(__renderAll)); } } function __registerAnimationEventHandlers() { var pre, prefixes = ['webkit', 'moz', 'o', 'ms']; // check vendor prefixes for (pre = prefixes.length - 1; pre >= 0 && !window.requestAnimationFrame; --pre) { window.requestAnimationFrame = window[prefixes[pre] + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[prefixes[pre] + 'CancelAnimationFrame'] || window[prefixes[pre] + 'CancelRequestAnimationFrame']; } // downlevel support via setTimeout / clearTimeout if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback) { // could likely be an adaptive set timeout return window.setTimeout(callback, 16.7); }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } } __registerAnimationEventHandlers(); // PUBLIC function add(renderer) { if (renderer) { renderers.push(renderer); } } function isRunning() { return !!interval; } function start() { interval = __mozFix(window.requestAnimationFrame(__renderAll)); } function stop() { if (!moz) { window.cancelAnimationFrame(interval); } interval = null; } // OBJECT DEFINITION return { "add": add, "isRunning": isRunning, "start": start, "stop": stop }; }());
I’ve put this code on jsFiddle to test out.
I’ve also put this on github as jsSimple. I’ll likely add a few other bits of code to this as I move along.