-
-
Save paulirish/1579671 to your computer and use it in GitHub Desktop.
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating | |
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel | |
// MIT license | |
(function() { | |
var lastTime = 0; | |
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 + timeToCall); }, | |
timeToCall); | |
lastTime = currTime + timeToCall; | |
return id; | |
}; | |
if (!window.cancelAnimationFrame) | |
window.cancelAnimationFrame = function(id) { | |
clearTimeout(id); | |
}; | |
}()); |
I did cleaned up the original a little bit:
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function (window, rAF, cAF) {
var lastTime = 0, vendors = ['ms', 'moz', 'webkit', 'o'], x;
for (x = 0; x < vendors.length && !window[rAF]; ++x) {
window[rAF] = window[vendors[x] + 'RequestAnimationFrame'];
window[cAF] = window[vendors[x] + 'CancelAnimationFrame']
|| window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window[rAF]) {
window[rAF] = function (callback) {
var currTime = new Date().getTime(),
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window[cAF]) {
window[cAF] = function (id) {
window.clearTimeout(id);
};
}
}(this, 'requestAnimationFrame', 'cancelAnimationFrame'));
which compresses to 423 bytes:
!function(a,b,c){var f,d=0,e=["ms","moz","webkit","o"];for(f=0;f<e.length&&!a[b];++f)a[b]=a[e[f]+"RequestAnimationFrame"],a[c]=a[e[f]+"CancelAnimationFrame"]||a[e[f]+"CancelRequestAnimationFrame"];a[b]||(a[b]=function(b){var c=(new Date).getTime(),e=Math.max(0,16-(c-d)),f=a.setTimeout(function(){b(c+e)},e);return d=c+e,f}),a[c]||(a[c]=function(b){a.clearTimeout(b)})}(this,"requestAnimationFrame","cancelAnimationFrame");
@paulirish - Is this being hosted somewhere new now? There are links to various repos, but I couldn't tell which one of them is "officially sanctioned".
@knod - As far as I can tell, the requestAnimationFrame polyfill-repo from @darius is the most up-to-date one.
If you want sub-millisecond precision, you can try adding the performance.now polyfill from @timhall after @darius's one. @timhall also uses the more compatible shorthand notation instead of Date.now().
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);
}
}
Currently, I found these :
- https://gist.github.com/mrdoob/838785#comment-792994
- https://gist.github.com/timhall/4078614
- https://github.com/kof/animation-frame
I can't tell which code is included in another one or not, and which is better... Maybe @kof has the answer ^^
I have created my library after reading all of this shims/polyfills. It includes all improvements and some additional features, like custom frame rate, feature detected raf (required in cases where raf is implemented but just doesn't work), using raf from the iframe, increased performance for multiple parallel animations when using non native version by grouping callback calls and using just one timer ...
Thanks a lot for your quick answer, now I can move forward in my project with serenity ;)
I think that the approach of using new timer for each callback can cause unexpected behaviour.
Say you have several elements you want to hide,
if each hide() will be on its own timer callback, they might get hidden not on the same frame
You can overcome this using callback queue and single timer.
(its not the full polyfill, just the way of work)
(function (global) {
var callbacksQueue = [];
global.setInterval(function () {
for (var i = 0; i < callbacksQueue.length; i++) {
if (callbacksQueue[i] !== false) {
callbacksQueue[i].call(null);
}
}
callbacksQueue = [];
}, 1000 / 60);
global.requestAnimationFrame = function (callback) {
return callbacksQueue.push(callback) - 1;
}
global.cancelAnimationFrame = function (id) {
callbacksQueue[id] = false;
}
}(window));
If you use JSLint:
/*global window*/
/*jslint maxlen: 100, plusplus: true, unparam: true */
(function () {
"use strict";
var lastTime = 0,
vendors = ['ms', 'moz', 'webkit', 'o'],
x;
for (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(),
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
id = window.setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
window.clearTimeout(id);
};
}
}());
What is the element
parameter?
window.requestAnimationFrame = function(callback, element) {
It's unused, and according to MDN the function takes just one argument.
To better match the timestamp passed to the requestAnimationFrame
callback (ie. window.performance.now()
), currTime
should be adjusted for the navigationStart
var currTime = new Date().getTime() - window.performance.timing.navigationStart;
Without this change my animations on IE9 were not correctly calculating compared to the browsers with native requestAnimationFrame
support.
Note: window.performance.timing
is only available on IE9+ (which really only applies to IE9 since requestAnimationFrame
is already available on IE10+
@davidchambers - It was removed from the spec - https://bugs.webkit.org/show_bug.cgi?id=74232
ES2015 flavored + performance.now()
{
const vendors = ['ms', 'moz', 'webkit', 'o']
const af = 'AnimationFrame'
let lastTime = 0
if('performance' in window == false)
window.performance = {}
if(!Date.now)
Date.now = () => new Date().getTime()
if ('now' in window.performance == false){
let nowOffset = Date.now()
if(performance.timing && performance.timing.navigationStart)
nowOffset = performance.timing.navigationStart
window.performance.now = () => Date.now() - nowOffset
}
for(let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
const vendor = vendors[x]
window.requestAnimationFrame = window[`${vendor}Request${af}`]
window.cancelAnimationFrame = window[`${vendor}Cancel${af}`] || window[`${vendor}CancelRequest${af}`]
}
if(!window.requestAnimationFrame){
window.requestAnimationFrame = callback =>{
const currTime = Date.now()
const timeToCall = Math.max(0, 16 - (currTime - lastTime))
const id = window.setTimeout(() => callback(currTime + timeToCall), timeToCall)
lastTime = currTime + timeToCall
return id
}
}
if(!window.cancelAnimationFrame)
window.cancelAnimationFrame = id => clearTimeout(id)
}
This was very helpful for me. Thanks! I'm using it in a generic animation library I wrote. I hope this is okay. https://github.com/imthenachoman/nAnimation
@imthenachoman Same issue as you, what's the license for this? I'm planning to use this in a game engine I'm writing.
@imthenachoman It says it's MIT license; you can probably do whatever you want.
Here's request-frame for anyone looking for a comprehensive solution that should just works on everything.
- npm / bower request-frame
- iOS6 fix without user-agent sniffing
- Normalizes firefox 4 - 10 for cancellation & predictability
- Polyfill native functions or keep intact via variables (To prevent conflicts with other API usage)
- IE 5.5+ (tested)
- AMD support
I believe it's best to use as few requestAnimationFrame instances as possible. I avoided frame rates and delays as they're better utilized outside of the polyfill, (vai the timestamp). Thanks to @darius for the timing tweaks, as well as everyone else on here.
[20:22:43] bower download https://gist.githubusercontent.com/paulirish/1579671/raw/3d42a3a76ed09890434a07be2212f376959e616f/rAF.js
Anyone else getting this:
Error 503 backend read error
backend read error
Guru Mediation:
Details: cache-lcy1125-LCY 1439843293 3968273849
Varnish cache server
Due to an unconfirmed bug in OldIE(maybe the poor performance), many tasks were delaying running.
There are two intended bad Fibonacci demos.
-
Check the original one in IE8(or lower version), then you may find that
timeToCall
is gradually growing bigger and bigger.I've made a little change to this code.
https://gist.github.com/lenville/9e13e63af075c145d662/revisions#diff-0// line 20 var timeToCall = Math.max(0, 16 - Math.abs(currTime - lastTime));
-
Check the revision.
In this article, David Geary implements a interesting version of polyfill.
http://www.ibm.com/developerworks/library/j-html5-game2/#N101B4
What do you think about it?
I've written a solution that doesn't queue each callback separately but execute all scheduled for next frame simultaneously:
https://github.com/milosdjakonovic/requestAnimationFrame-polyfill
Second (third, fourth...) opinion and eyeball check would do good.
In most situations I use miniraf ✨
Maybe I'm still missing something but for me the polyfill is not working right now and I am triong to figure out what is missing
Uncaught SyntaxError: Missing initializer in const declaration
Hai , i am new to angular2. i have a conflict in loading the angular2 webapp in safari browser. Actually where to use this code in the code so that i can get rid of this browser problem. is this also the solution for improper loading of c3 charts in certain browsers like safari and microsoft edge. please help me out and thanks in advance.
Hi Vennapusaravali,
More suitable for the Angular 4 repo, however if you checkout this JS file and add the script to angular-cli.jsons "scripts": [ ".../path/to/this/file/rAF.js" ] it should load correctly. More info can be found here.
Hello, can someone help me with a question in my website? I don't know where is the issue list, or who I can ask. My website is not working the parallax.js (http://memphisnet.com.br/3.0/)
Thanks advice
Hi guys,
Anyone know the answer to this question: https://stackoverflow.com/questions/52508261/do-we-need-to-clear-a-timeout-when-using-requestanimationframe-polyfill ? Would like to hear a professional opinion.
Thanks
I've been reading a lot of the comments but I am kinda bit confused now which code to be implemented.
Hello,
I just adapted Paul Irish's polyfill to work with high resolution timing automatically (when possible) and improved the performance a little bit.
It can work with the following window.performance.now polyfill: https://gist.github.com/jalbam/cc805ac3cfe14004ecdf323159ecf40e
Here it is:
'use strict';
// requestAnimationFrame polyfill by Erik Möller.
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavic, Darius Bacon and Joan Alba Maldonado.
// Adapted from https://gist.github.com/paulirish/1579671 which derived from
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// Added high resolution timing. This window.performance.now() polyfill can be used: https://gist.github.com/jalbam/cc805ac3cfe14004ecdf323159ecf40e
// MIT license
// Gist: https://gist.github.com/jalbam/5fe05443270fa6d8136238ec72accbc0
(function() {
var vendors = ['webkit', 'moz', 'ms', 'o'], vp = null;
for (var x = 0; x < vendors.length && !window.requestAnimationFrame && !window.cancelAnimationFrame; x++)
{
vp = vendors[x];
window.requestAnimationFrame = window.requestAnimationFrame || window[vp + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window.cancelAnimationFrame || window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame'];
}
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) //iOS6 is buggy.
{
var lastTime = 0;
window.requestAnimationFrame = function(callback, element)
{
var now = window.performance.now();
var nextTime = Math.max(lastTime + 16, now);
return setTimeout(function() { callback(lastTime = nextTime); }, nextTime - now);
};
window.cancelAnimationFrame = clearTimeout;
}
}());
You can found it in this gist: https://gist.github.com/jalbam/5fe05443270fa6d8136238ec72accbc0
Any comments are welcome. Thank you very much.
FWIW, -o-requestAnimationFrame and -ms-requestAnimationFrame have never been used. Both browsers (IE 10+ and Opera 15+) use the unprefixed version. Firefox supports the unprefixed version since FF23, which was released last August (we are now 3 versions further).
So lines 10-15 can be rewritten to: