Up to date polyfill for requestAnimationFrame
Asked Answered
V

5

8

http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision tells me that recently (Chrome 20) requestAnimationFrame has gained a new sub-millisecond precision timer, and that I have to update my code to support it.

Looking around at the various polyfills around, they all seem to pre-date this update. Are they somehow functional (I don't think so), or is there simply not an up-to-date one available? Should I just do the timing myself (seems a bit wasteful).

Voluble answered 5/11, 2012 at 22:17 Comment(2)
I don't think it's possible to get a sub-millisecond-timer to work without the new APIsFrankly
We plan on pushing this change out in Chrome 21, so if you're already taking advantage of this callback parameter, be sure to update your code! - not Chrome 20, you still have time.Kop
J
3

I had just read that article too and was curious to try this myself. I've taken a stab at adding a wrapper to the rAF callback in browsers that don't support high-resolution timers. It uses Paul Irish's original polyfill with the following added lines:

var hasPerformance = !!(window.performance && window.performance.now);

// Add new wrapper for browsers that don't have performance
if (!hasPerformance) {
    // Store reference to existing rAF and initial startTime
    var rAF = window.requestAnimationFrame,
        startTime = +new Date;

    // Override window rAF to include wrapped callback
    window.requestAnimationFrame = function (callback, element) {
        // Wrap the given callback to pass in performance timestamp
        var wrapped = function (timestamp) {
            // Get performance-style timestamp
            var performanceTimestamp = (timestamp < 1e12) 
                ? timestamp 
                : timestamp - startTime;

            return callback(performanceTimestamp);
        };

        // Call original rAF with wrapped callback
        rAF(wrapped, element);
    }        
}

Here's a gist of it all combined together and an updated example using the new code:

https://gist.github.com/4078614

http://jsfiddle.net/timhall/XQpzU/4351/

This approach aims at normalizing the parameter that is passed into the callback function to the high-resolution timer format. You could use a similar approach, just opposite, to convert the high-resolution timer to the old format if you have existing code expecting that, but I see that as a regression.

I'm going to try it out in one of my projects that I'm working on right now and will update the gist if I find any issues / improvements.

Joung answered 15/11, 2012 at 13:23 Comment(0)
H
2

The change for hi-res timing only affects the parameter to the callback. I don't believe any polyfills explicitly reference the parameter, it just depends on how you use it. So the polyfills don't need updating and should be working just fine already - just be careful about how you use the parameter to the RAF callback, and if you don't, it's nothing to worry about!

Hangdog answered 11/11, 2012 at 20:24 Comment(1)
While the polyfills do work fine, if I ignore the parameter, I would prefer to use it where possible, else why introduce the new parameter?Voluble
G
1

this might work. modified this gist

https://gist.github.com/1579671

(function() {
    var lastTime = 0;
    var startTime = Date().getTime();
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 
                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime - startTime); }, 
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());

get the timestamp when the closure first executes (page load), then pass into the callback the difference between the current timestamp and the original. Should give you an integer equivalent of the new method. Not as precise, but better than a totally different value.

Gifu answered 15/11, 2012 at 13:10 Comment(1)
Thanks for this. Unfortunately I do not have the chance to test this carefully at the moment, but this looks good!Voluble
H
1

Here is the blog entry from Paul Irish containing the original polyfil and his updates.

http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

That should suffice for most scenarios.

Horse answered 31/5, 2016 at 15:16 Comment(0)
E
-2

Paul Irish has suggested a polyfill for this.

window.requestAminFrame = (function(){
    return window.requestAminFrame || window.webkitRequestAnimFrame || window.mozRequestAnimFrame || window.msRequestAnimFrame || window.oRequestAnimFrame || function(func){return setTimeout(func,1/60);};
})();
Ennead answered 14/11, 2012 at 12:20 Comment(1)
There is no window.requestAminFrame. It's window.requestAnimationFrameIambus

© 2022 - 2024 — McMap. All rights reserved.