Get up to 80 % extra points for free! More info:

Lesson 16 - JS requestAnimationFrame - For better drawing

In the previous exercise, Solved tasks for JavaScript lesson 15, we've practiced our knowledge from previous lessons.

The previous lesson, Solved tasks for JavaScript lesson 15, was about animations. Together with HTML5, a new JavaScript API - requestAnimati­onFrame has been added. It's a technology that allows us to render animations in the browser more fluently and with higher performance. We'll introduce the technology in today's JavaScript tutorial.

If you ever tried to program a simple browser game, your main loop might looked like this.

setInterval(function() {
    update();
    render();
}, 1000 / FPS);

Our previous animations looked very similar, we only combined updating and rendering into a single function. An alternative rendering loop may also look like this:

function loop() {
    setTimeout(loop, 1000 / FPS);
    update();
    render();
}
loop();

The code works, we can even limit FPS. So what's wrong with it?

Wasting computing power

The problem with the code above is that the browser invokes it even if the user is not looking at the page (they switched to another tab or minimized the browser). The Google Chrome browser handles these situations by restricting such loops to only 1 FPS. But this is only its voluntary behavior, and other browsers might not do it. We may experience unnecessary performance drops and discharges on mobile devices.

requestAnimationFrame solves it!

Using the requestAnimationFrame() function instead of setTimeout(), our code will look very similarly.

function loop() {
    requestAnimationFrame(loop);
    update();
    render();
}
loop();

Mozilla invented this feature and the WebKit team later took over and improved it. We can use it to draw CSS, DOM elements, WebGL, or on canvas.

Advantages

requestAnimationFrame() will ensure that all of our animations are rendered at once, with higher performance and lower battery consumption.

If you switch to another tab in your browser or you minimize the browser, the rendering will stop to save power and will continue as soon as the page is visible again.

You may have also noticed that using requestAnimationFrame() we have never set the number of FPS. By default, the function uses 60 FPS, but it depends on the browser implementation. However, it should not be too different and it depends on the PC's performance rather than on the browser creator's decision. Also, the support across browsers is quite good.

Demo

At the end, we'll show a simple application in which a square moves on a canvas. We'll implement it using both setInterval() and requestAnimationFrame(). We won't clear the canvas this time on purpose, so we'll see the square's trace.

The solution using setInterval()

window.onload = function() {
    let canvas = document.querySelector("#canvas");
    let context = canvas.getContext("2d");
    let square = {
        "x": 25,
        "y": 25,
        "dirX": -1,
        "dirY": 1,
        "speed": 2,
        "sizeX": 50,
        "sizeY": 50,
        "color": "red"
    };

    function loop() {
        update();
        render();
    }
    setInterval(function() {
        update();
        render();
    }, 1000 / 60);
    loop();


    function update() {
        if (square.x + square.sizeX + square.speed * square.dirX > canvas.width)
            square.dirX = -1;
        if (square.x + square.speed * square.dirX < 0)
            square.dirX = 1;
        if (square.y + square.sizeY + square.speed * square.dirY > canvas.height)
            square.dirY = -1;
        if (square.y + square.speed * square.dirY < 0) square.dirY = 1;

        changeColor();
        square.x += square.speed * square.dirX;
        square.y += square.speed * square.dirY;
    }

    function render() {
        context.fillStyle = square.color;
        context.fillRect(square.x, square.y, square.sizeX, square.sizeY);
    }

    function changeColor() {
        colors = ['green', 'blue', 'red', 'yellow'];
        square.color = colors[Math.floor(Math.random() * colors.length)];
    }
}

The result:

An animation using setInterval
localhost

The solution using requestAnimationFrame()

window.onload = function() {
    let canvas = document.querySelector("#canvas");
    let context = canvas.getContext("2d");
    let square = {
        "x": 25,
        "y": 25,
        "dirX": -1,
        "dirY": 1,
        "speed": 2,
        "sizeX": 50,
        "sizeY": 50,
        "color": "red"
    };

    function loop() {
        update();
        render();
        requestAnimationFrame(loop);
    }
    loop();

    function update() {
        if (square.x + square.sizeX + square.speed * square.dirX > canvas.width)    square.dirX = -1;
        if (square.x + square.speed * square.dirX < 0)
            square.dirX = 1;
        if (square.y + square.sizeY + square.speed * square.dirY > canvas.height)   square.dirY = -1;
        if (square.y + square.speed * square.dirY < 0)
            square.dirY = 1;

        changeColor();
        square.x += square.speed * square.dirX;
        square.y += square.speed * square.dirY;
    }

    function render() {
        context.fillStyle = square.color;
        context.fillRect(square.x, square.y, square.sizeX, square.sizeY);
    }

    function changeColor() {
        colors = ['green', 'blue', 'red', 'yellow'];
        square.color = colors[Math.floor(Math.random() * colors.length)];
    }
}

The result:

An animation using requestAnimati­onFrame
localhost

I hope the lesson has been useful for you and you will be using requestAnimationFrame() in your animations :)

In the next lesson, Strict operators and casting in JavaScript, we'll talk about conditions before embarking on another bigger topic - working with graphics.


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 5x (3.33 kB)
Application includes source codes in language JavaScript

 

Previous article
Solved tasks for JavaScript lesson 15
All articles in this section
JavaScript Basic Constructs
Skip article
(not recommended)
Strict operators and casting in JavaScript
Article has been written for you by David Capka Hartinger
Avatar
User rating:
1 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities