Make a fancy animated HTML5 Logo for your WordPress with pure JS (2/3)

Today is all about animations. In simple terms, animation is movement over time.
However, we won’t change multiple images over time as it is known from the cartoon, but animate parts of one entity on the canvas.
Tha basis for this will be the stickman (or our own logo) which we created in part I of this series.

What we need right now is:

  1. a movement specification – which parts are animated and in which way
  2. a time interval – how long will the animation run
  3. the animation speed –  how much movement do we want to have in one timeframe

E) Animation Now and Then

Animations are nothing new to the JavaScript world. Previously, one would have used timers like setTimeout() or setInterval() to create an animation loop but both have serious downsides:

  • The animation may be drawn regardless of whether the browser tab is visible, minimized, switched, scrolled..
  • ..this causes wasted CPU cycles..
  • ..and draining batteries
  • Animation loops are long-running tasks which block UI since JavaScript is single-threaded. This in turn makes applications unresponsive: clicks, swipes, etc. are ignored/queued
  • Animations are overdrawn, that is if the animation runs faster than the refresh rate of the monitor a frame may be redrawn/computed before it is displayed on the monitor – those frames are lost and the animation gets choppy
  • Multiple animations cause extra problems since they may overlap and are not synced with the monitor

For this reason the requestAnimationFrame() API was introduced in modern browsers. As the name suggests, you “lose” control of when your animation method is called and leave it to the browser – you have to request a frame. But as bad as this sounds, the browser should be the only instance capable of deciding the best time for your animation.

requestAnimationFrame requires one argument which is a function. This function is called whenever the browser decides that it would be a good time to redraw. Let’s see how it works:

F) A Simple Animation

The current drawLaserBeams method is too static so we will remove this code:

And replace it with our first animation:

simplest animation

Using requestAnimationFrame we created some kind of browser scheduled loop similar to while(true){}.
This is called an animation loop and it will constantly call drawDash() and increment the distance from the starting point to next drawn dash.

The problem with the above code is, that it similar to while(true){} will run to all eternity (or until the browser tab is closed).

So far we’ve defined the “what” – we specified which parts are animated (and in which way) but the speed and the duration are more or less arbitrary.

G) Time Controlled Animations

This part is about “when” and “how often” our animation is repainted, that is how fast and smooth it is.
Let’s have a look on this example:

requestAnimationFrame Interval

So how often gets the draw function in the above code called? That all depends on your browser and computer, but typically it’s 60fps which is due to the fact that most monitors refresh with 60Hz. So instead of determing the interval for our animation we leave it to the browser to calcualte the next available opportunity – which is hopefully 60Hz. Sometimes it is less which might be effected by the browser taking element visibility, CPU load, battery or a lower display rate into account.

Notes on Frames Per Second
“Frame rate, also known as frame frequency and frames per second (FPS), is the frequency (rate) at which an imaging device produces unique consecutive images called frames.”(Wikipedia)

The desired FPS depend on the perception of the viewer. The human body has some capacity with which it can receive information and which it needs to perceive a sequence of displayed images as a smooth animation. There is a discussion which frame rate still represents an optimization but a rule of thumb is that a smooth animation can be reached with 30 FPS. 60 FPS are optimal for most devices, everything above 60 FPS is overdrawn on most devices and therefore never displayed.

However, one should ensure that the animations withstand this requirement. Keeping this in mind, with ideal 60 FPS we have a repaint every 16,7 ms.
monitor (My monitor settings showing 60Hz)

Empirical Measurement
With the code above, we can now visualize the actually achieved “repaint rate”:

timeline_comparison.fw

For the sake of simplicity, I compared the results to an “ideal” frame rate of 62 FPS which is one frame every 16ms.
As can be seen in the timeline, the animate method reaches 53 FPS in this test run. But what is even more interesting is the spreading and its effect on the perception of our animation:

As can be seen, the animation has a “slow start”, that means it is really choppy in the beginning with considerably less function calls and needs some time to achieve a steady refreshing rate. Another problem with the above code is that the animation speed highly depends on your device and the running tasks.

Consider the laser beam animation which has only a few frames. On a fast device with an ideal frame rate it would finish after ~160ms that is with high speed. Now compare it to my test run – it would be unfinshed after 240ms. On tablets or smartphones the same animation with the same code would for sure take conspicuously longer.

speed_comparison

Defining Frames

To fix the performance gap between different devices and to have a smooth and device independent animation we have to throttle the animation speed by “overwriting” the maximum speed with our own frame rate.

Thus, to define a speed and duration, as intended in the beginning, our construct is not enough. In order to achieve a more consistent speed in our image changes, we have to stretch such changes over multiple animation frame cycles. The animation is slowed down but getting smoother.

So instead of leaving the actual FPS completely to the browser we calculate our own speed in the following way:

The longest beam has 10 dashes. For my desired animation duration 2 seconds should make a good start. This results in 200ms per update.
Please note that in this example the actually displayed frames are reduced to 5 per second(5 FPS) even if ~50 FPS would also be possible.

max_fps_and_frames

As the timeline illustrates, using this method we have a much more consistent and smotth animation. However, our frames do not macth exactly on the browser scheduled frames. But the gaps are not glitches in our animation. Some frames are stretched – they are longer displayed than intended, but there is no frame which is shorter than 200ms…
As you can see, even this approach is not perfect but I do not want to go too far into detail. The above method should be enough for our purpose.
We are now able to define the animation itself, a speed and the duration. Here is the final drawNextDash() method:

the animation loop:

and the final result:

Result

In the next and final part we will clean everything up, make it more object-oriented + responsive and integrate it in our Worpress!

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload the CAPTCHA.