Martijn Ven van de Martijn Ven van de - 5 months ago 16
Javascript Question

Smooth Animation in HTML5 Canvas

Well I have edited this question because it was a duplicate.

Answer

requestAnimationFrame

For full details see MDN window.requestAnimationFrame

As the previous answer is lacking some information, here is annotated example of the basic usage.

// A flag to indicate that the animation is over
var stop = false; // when true the animation will stop

// define main loop update
// the callback that is the main loop
// the browser treats this function as special in terms of display items including
// the canvas, and all DOM items.
// It will ensure that any changes you make to the page are synced to the display
function update(time){  // time is the time since load in millisecond 1/1000th
                        // time is high precision and gives the time down to
                        // microseconds (1/1,000,000) as fraction 0.001 is one microsecond

    // you can stop the animation by simply not calling the request
    // so if the flag stop is true stop the animation
    if(!stop){
        requestAnimationFrame(update); // request the next frame   
    }
}

requestAnimationFrame(update); // request the very first frame 
// or you can start it with a direct call. But you will have to add the time
update(0);

The update function will be called up to 60 times a second. If the code can not keep up (ie it take more than 1/60th of a second to render) then the update function will wait for the next frame effectively reducing the frame rate to 1/30. It will continue skipping frames if the render is slow.

Because you can not control the frame rate you can do the following to slow the animation down to a required frame rate.

const FRAMES_PER_SECOND = 30;  // Valid values are 60,30,20,15,10
// set the mim time to render the next frame
const FRAME_MIN_TIME = (1000/60) * (60 / FRAMES_PER_SECOND) - (1000/60) * 0.5;
var lastFrameTime = 0;  // the last frame time
function update(time){
    if(time-lastFrameTime < FRAME_MIN_TIME){ //skip the frame if the call is to early
        requestAnimationFrame(update);
        return; // return as there is nothing to do
    }
    lastFrameTime = time; // remember the time of the rendered frame
    // render the frame
    requestAnimationFrame(update);
}

If you change the focus to a another tab the browser will no longer call the request until focus is returned to the tab.

Like other timer events the call requestAnimationFrame returns a ID that can be used to cancel the callback event

var id = requestAnimationFrame(update);
// to cancel 
cancelAnimationFrame(id);

You can actually call requestAnimationFrame more than once per frame. As long as all the requests can render within the 1/60th of a second they all will by synced and presented to the display at the same time. But you must be careful because they can come out of sync if the rendering time is too long.

RequestAnimationFrame prevents flickering (displaying the canvas when the rendering is not complete) by double buffering changes. Syncs to the display hardware and prevents shearing (caused when the display is updated midway through a frame and the top half of the display shows the old frame and bottom the new frame). There are more benefits depending on the browser.

Comments