Animating with Canvas

Lately I’ve been trying to get more familiar with the canvas API. My first project was an attempt at recreating AfterDark’s “flying toaster” screensaver. Bryan Braun previously recreated it with CSS.

Key things I learned along the way

HTMLImageElement

Canvas can reference images that are already on the page, but rather than embed an image just to hide it, you can also create a new HTMLImageElement and set the src attribute, creating the image on the fly. From there, drawImage() accepts parameters to draw only a portion of the image. This allows you to crop the image on the fly as well and use a sprite for the animation.

setInterval

In my first attempt, I used window.requestAnimationFrame() to animate the toasters. However, this made the toasters move way too fast, and moved them all at the same speed. Switching to setInterval() let me set and randomize the speed at which the toasters moved. Moving the toasters themselves was fairly simple. I cleared the existing image with clearRect(), moved the toaster four pixels down and four pixels to the right, and then redrew it, sliced at the next stage of the sprite.

Using the sprite

Another mistake I made in the first attempt was simply looping through the sprite. This caused a weird jump because the end position of the toaster’s wings was different from the first position. What I actually needed to do was run forwards and then backwards through the sprite, so the wings would appear to move up and down smoothly. I set a flag, direction, equal to either up (wings moving up) or down (wings moving down), to determine whether the next slice should be drawn to the left or the right of the current slice.

Introducing randomness

I made heavy use of a pseudo-random number generator to vary the animation. The type of object (toaster or toast), speed, and starting position are all selected randomly. I weighted the object type by randomly choosing an integer between 0 and 2, with 0 being toast and 1 or 2 being toaster, so there would on average be more toasters than toast. Likewise, I weighted the speed so that there would on average be more objects moving at the middle speed.

The downside of random positioning is that the toasters and toast occasionally fly into one another. If I create a future version, I’ll want to account for the other objects’ positions and adjust accordingly.

While I don’t think a project is likely to require flying toasters any time soon, I’m interested in working with canvas more as another option for drawing and animation, instead of or in addition to SVG and CSS.

References