Canvas – Animation

Outside of the canvas api but part of HTML5, the widely supported requestAnimationFrame method replaces the old setInterval() and setTimeout() functions of the past for browser animation. A basic setup is as follows:

var start, elapsed, fps;

function animate(timestamp) {
    if (!start) start = timestamp; // first time
    elapsed = timestamp - start;
    start = timestamp;             // reset baseline
    fps = 1000 / elapsed;
    window.requestAnimationFrame(animate);
}

window.requestAnimationFrame(animate);

The animate function fires at whatever the browser determines is an optimal framerate, generally 60 times a second. If a browser tab running animate code is not visible, it may not be called at all (chrome), or may be called once a second (firefox); the actual behavior of browsers in this situation is unspecified. A timestamp is passed as an argument to the callback routine set to a value from Performance.now()  at the time the callback was triggered.

With this timestamp value,  we can calculate effective frames per second and make adjustments to ensure animations run at a constant rate. Or we can use elapsed time to perform actions once a second or in intervals other than the framerate.

To move at a certain number of pixels per second, regardless of the framerate:

ball.vx * (elapsedTime / 1000);
ball.vy * (elapsedTime / 1000);

Where ball.vx and ball.vy = the number of pixels per second.

To finesse the timing of a sweeping second-hand, we can calculate the number of radians traversed per second by chopping a circle up into 60 segments: 2PI/60 and then increment the angle based on how much of the second has elapsed:

angle += 2PI/60 * (elapsed/1000);

To start the second-hand at a specific angle, like current seconds, it can be initialized like so:

angle = (Math.PI*2) * (new Date().getSeconds()/60) - Math.PI/2;

This adjusts for the fact that radian = 0 is actually at the 3 o’clock position of a circle, or 90 degrees.

Instead of hardcoding 60, any divisor from 0..n could be used to map the value n to its corresponding location on the circle.

The following experiment animates the second-hand as a line from the center to its time corrected position along the circumference each frame. This creates a smooth, sweeping movement. Another function plots the location of the current hour, displaying it as a translucent circle and displays the minutes numerically inside.

(Using text with canvas wasn’t covered yet, but is explained well here. Note also that two canvas elements are used and stacked one upon another using css. This allows the dial to be drawn once to improve performance, since it doesn’t change, and leverages the default transparency of a canvas.

See the Pen Clock by Kentskyo (@kentskyo) on CodePen.0