HTML5’s Canvas and CanvasRenderingContext2d bring something to HTML5 that has long been missing from HTML: the ability to draw pixels into a browser window. I wrote about the canvas API in a previous post entitled Making HTML5 Come Alive with the Canvas API. This time, I’d like to build on that post by exploring a subject for which HTML5 provides no native support: canvas animations.

Silverlight has a robust animation engine built in that makes it easy to make objects move around the screen. HTML5 does not, but you can use timer functions to move objects around by repositioning them at regular intervals. Because HTML5’s canvas API is an immediate-mode drawing API (as opposed to Silverlight’s retained-mode API), moving an object from one position to another requires you to erase it from its current position before drawing it in its new position. Erase, draw, repeat – that’s the basic technique for animating movement within a canvas in HTML5. But as you’ll see, it’s possible to animate CSS properties of the canvas itself to lend the whole affair a retained-mode feel.

For a demonstration, point an HTML5 browser such as Internet Explorer 9, Firefox 4, Chrome 10, Opera 11, or Safari 5 to http://www.wintellect.com/html5/MovingAnimation1.html. You’ll see a page containing a red ball that measures 100 pixels in diameter bouncing around in a 400×400 canvas:

Animation1

Here’s the code that animates the red ball. Every 10 milliseconds or so, the move function erases the ball by calling CanvasRenderingContext2d’s clearRect method. Then it computes the ball’s new position and draws a red circle there. Like frames in a video, it creates the illusion of motion:

 

// Set a timer to fire every 10 milliseconds

setInterval("move()", 10);

 

function move() {

    // Erase the circle from its old position

    _dc.clearRect(_x – 50, _y – 50, 100, 100);

 

    // Compute the circle’s new position

    var x = _x + _dx;

 

    if (x < 51 || x > (_cx – 51)) {

        x = _x – _dx;

        _dx = -_dx;

    }

 

    var y = _y + _dy;

 

    if (y < 51 || y > (_cy – 51)) {

        y = _y – _dy;

        _dy = -_dy;

    }

 

    _x = x;

    _y = y;

 

    // Redraw the circle in its new position

    _dc.fillStyle = "red";

    _dc.beginPath();

    _dc.arc(_x, _y, 50, 0, Math.PI * 2, true);

    _dc.fill();

}

 

Nothing hard about that. And one of the nice things about clearRect is that works equally well against complex backgrounds. To see what I mean, check out the page at http://www.wintellect.com/html5/MovingAnimation2.html. Unlike its predecessor, it animates a ball against a background consisting of a wood-grain image. For good measure, it also uses a radial gradient fill to make the ball look a little more realistic:

Animation2

While there’s nothing inherently wrong with animating an object this way, developers used to retained-mode graphics subsystems will come away feeling a little cold. Wouldn’t it be nice if there were a way draw the ball once and then move it around the screen without having to continually erase and redraw it? Funny you should ask. Because with a little help from CSS, you can do just that.

The third example in this series – http://www.wintellect.com/html5/MovingAnimation3.html – does things a little differently. It looks the same on the outside, but on the inside, instead of erasing and redrawing a ball in a 400×400 canvas, it draws the ball once in a 100×100 canvas. Then it uses a timer function to animate the canvas’s CSS left and top properties. Now the browser takes care of doing the erasing and redrawing. Here’s the modified move function:

 

function move() {

    // Get the ball’s current position

    var left = _canvas.style.left;

    var top = _canvas.style.top;

 

    var x = parseInt(left.substring(0, left.length – 2));

    var y = parseInt(top.substring(0, top.length – 2));

 

    // Compute the ball’s new position

    x += _dx;

 

    if (x < 0 || x > (_cx – 101)) {

        _dx = -_dx;

        x += (2 * _dx);

    }

 

    y += _dy;

 

    if (y < 0 || y > (_cy – 101)) {

        _dy = -_dy;

        y += (2 * _dy);

    }

 

    // Move the ball to its new position

    _canvas.style.left = x + "px";

    _canvas.style.top = y + "px";

}

 

Animating the canvas position rather than animating the position of something within the canvas is a huge step in the right direction. And it has the added advantage that it allows the browser to use the GPU to move pixels around the screen – something the browser cannot do when your code is continually erasing and redrawing. Keep this in mind when building animations in HTML5.