Home  >  Article  >  Web Front-end  >  Easing function requestAnimationFrame better implements browser animation_Basic knowledge

Easing function requestAnimationFrame better implements browser animation_Basic knowledge

WBOY
WBOYOriginal
2016-05-16 17:47:22971browse

The requestAnimationFrame function is used to write the easing function. I have learned about it before, but I always feel that I don’t understand it very well, so I translated an article written by a foreigner for the purpose of learning and sharing.

What is requestAnimationFrame?
In the past, when we did animation, we needed a timer to make some changes every millisecond. Now there is good news: browser manufacturers have decided to provide a method specifically for animation, namely requestAnimationFrame(), and it can also be better optimized at the browser level. However, this is only a basic API for animation, that is, it is not based on style changes of DOM elements, nor is it based on canvas or WebGL. Therefore, we need to write the specific animation details ourselves.

Why should we use it?
For n animations running at the same time, the browser can optimize and optimize the original N times of reflow and repaint into 1 time, thus achieving high-quality animation. For example, there are JS-based animations, CSS-based transitions, or SVG SMIL. Plus. If a tab in the browser is running such an animation, and then you switch to another tab, or simply minimize it, In short, if you can't see it, the browser will stop the animation. This will mean less CPU, GPU and less memory consumption, resulting in significantly longer battery life.

How to use it?

Copy code The code is as follows:

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame | |
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
// usage:
// instead of setInterval(render, 16) ....
(function animloop(){
render();
requestAnimFrame(animloop, element);
})();

Note: I used "requestAnimFrame" here because the specification is still changing and I don't want to be at the mercy of the specification.
requestAnimationFrame API
Copy code The code is as follows:

window.requestAnimationFrame(function(/ * time */ time){
// time ~= new Date // the unix time
}, /* optional bounding elem */ elem);

Give Chrome first and Firefox version
Copy code The code is as follows:

window.mozRequestAnimationFrame([callback]) ; // Firefox
window.webkitRequestAnimationFrame(callback[, element]); // Chrome

Parameters:
callback: (FF optional, Chrome required)
Next The function called by repaint, the first parameter of the function is the current time
element: (FF None)
Let’s paraphrase it: it is actually the canvas, and the ‘painting’ is animation. (the element that visually bounds the entire animation). For canvas and WebGL, it is the element. For DOM nodes, you can ignore it. If you want to optimize it a little, you can also pass in a parameter.

Is it reliable?
Now, there are some differences between the Webkit implementation (available in Nightly Safari and Chrome Dev Channel) and the Mozilla implementation (available in FF4), and the Mozilla implementation has a bug. In fact, the number of frames of FF animation is calculated like this: 1000/(16 N) fps, where N is the execution time of callback in milliseconds. If your callback execution time is 1000ms, then its highest frame rate is only 1fps. If your callback execution time is 1ms, then the frame rate is almost 60fps. This bug will definitely be fixed, maybe in the next version of FF4. Chrome10 does not have a time parameter (added in m11. I would like to ask, what is m11?), and FF currently does not have an element parameter.
I looked at the bug in Firefox, and it probably means:
FF's mozRequestAnimationFrame() can never reach 60fps, even if your callback execution time is less than 1000/60 milliseconds. For example:
Copy code The code is as follows:

function callback(time) {
window.mozRequestAnimationFrame(callback);
doWork();
}

If doWork() takes 1000/60 milliseconds, then the frame rate is about 30fps, and if the same animation uses setTimeout(callback, 16), the frame rate is 60fps. It seems that the callback always starts executing again about 16ms after the callback is executed, rather than 16ms after the callback starts executing. If it is the latter, and the calculation is fast enough, it can produce 60fps frames.
If you are a standard control, the portal is here



Without further ado, let’s start with a classic animation function:
Copy code The code is as follows:

function animate(element, name, from, to, time) {
time = time || 800; //Default 0.8 seconds
var style = element.style,
latency = 60, //Change every 60ms
count = time / latency, //Number of changes
step = Math.round((to - from) / count), //The amount of change in each step
now = from;
function go() {
count--;
now = count ? now step : to;
style[name] = now 'px';
if (count) {
setTimeout(go, latency);
}
}
style [name] = from 'px';
setTimeout(go, latency);
}

Regardless of the limitations of the design of this function, such as it can only be set in px as the unit Modify the style. From the perspective of function implementation alone, this can be a very classic animation concept. Its basic logic consists of the following parts:
Get the starting point value from and the end point value to, the time required for animation, and the interval between each detection Latency requirements, calculate the number of times the value changes count and the amount of each change step.
Enable setTimeout(fn, latency); to step to the next detection.

In the next detection, set the attribute step once. If the animation has not ended yet, go back to step 2 to continue the next detection.
This function works very well and serves thousands of sites and systems. In fact, the core of jQuery’s animate function is nothing more than the setInterval function.
However, with the steady increase in the complexity of the current system, there are more and more animation effects, and more attention is paid to the smoothness of the animation, which leads to some problems with the above function. For example, if 100 animation effects are turned on at the same time, according to the above function, it is obvious that 100 timers will be running at the same time, and the scheduling between these timers will have a slight impact on performance. Although in a normal environment, these small effects will not matter, in an environment such as animation that has high requirements for fluency, any subtle impact may produce a bad user experience.

Under such circumstances, some developers have invented an animation framework based on unified frame management. They use a timer to trigger animation frames, and different animations register these frames in each frame. Handle multiple animated property changes. The advantage of this is that it reduces the overhead of timer scheduling, but for animation framework developers, unified frame management and APIs for monitoring frames need to be developed and maintained.

Direct browser support
In the end, browser manufacturers found that this can actually be done by them, and based on the browser level, there can be more optimizations , for example:
For all operations on the DOM in one survey, Layout and Paint are only performed once.
If the animated element is hidden, then Paint will not be performed.
As a result, browsers began to launch an API called requestAnimationFrame. Regarding this function, the relevant pages of MDC have a more detailed introduction. Simply put, there are two ways to use this function:
Call the requestAnimationFrame function and pass a callback parameter, callback will be called in the next animation frame.
Call this function directly without passing parameters to start the animation frame. When the next frame is triggered, the window.onmozbeforepaint event will be triggered at the same time. You can animate by registering this event.

The second method relies on Firefox’s own events, and the beforepaint event has not yet entered the standard, so it is not recommended. It is better to use the first method. At this time, our animation logic can become like this:
Record the current time startTime as the time when the animation starts.
Request the next frame with a callback function.
When the next frame is triggered, the first parameter of the callback function is the current time, which is then compared with startTime to determine the time interval ellapseTime.
Judge whether ellapseTime has exceeded the preset animation time. If it exceeds, end the animation.
Calculate the difference of animation attribute changes differ = to - from, and then determine how much step should change during ellapseTime = differ / time * ellapseTime.
Calculate the position Math.round(from step) that should change to now, and reassign the style.
Continue requesting the next frame.

New animation function
The following is a brand new animation function:
Copy code The code is as follows:

function animate(element, name, from, to, time) {
time = time || 800; // Default 0.8 seconds
var style = element.style,
startTime = new Date;
function go(timestamp) {
var progress = timestamp - startTime;
if (progress >= duration) {
style[name] = to 'px';
return;
}
var now = (to - from) * (progress / duration);
style[name] = now.toFixed() 'px';
requestAnimationFrame(go);
}
style[name] = from 'px';
requestAnimationFrame(go);
}

At this point, there is one problem left, that is, it is not Every browser supports the requestAnimationFrame function, so make a simple correction.
According to the characteristics of Firefox, the highest FPS provided by mozRequestAnimationFrame is 60, and it will be adjusted according to the calculation time of each frame. For example, if each frame takes 1s to calculate, it will only provide 1FPS. animation effects.
The higher version of Chrome also implements this function, called webkitRequestAnimationFrame. It is foreseeable that there will be Opera's oRequestAnimationFrame and IE's msRequestAnimationFrame in the future, so here is a simple compatibility process:
Copy code The code is as follows:

requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window .webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) { setTimeout(callback, 1000 / 60); };
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn