The Unfortunate State of Canvas Animations on the iPhone / iPadPosted on by Adam Grossman
Over the next several months, Jack and I will be building a series of fun little interactive online games for a client. In years past, these type of (animation-heavy) games would have undoubtedly been built in Flash. Our client, however, is forward-thinking enough to let us try ditching Flash and implementing them all with HTML / CSS / JS (a.k.a. “HTML5”).
Part of the rationale of moving away from Flash is that we want (at least some of) these games to be playable on the iPad and iPhone. The target demographic is younger school-age kids, and the iPad is poised to take off in that space.
Now, when it comes to building rich, graphical, animated games in HTML5, the obvious first step is to investigate Canvas. We’ve done so, and we’ve come to a couple conclusions:
- Canvas is entirely unsuited to generating full-screen animations on any iOS device. The frame-rates are unacceptably low.
- Clearing the canvas between frames is surprisingly expensive.
Here’s the test I used, so you can try it out yourself:
It’s pretty much the simplest animation you can perform with canvas... drawing a single circle moving across the screen.
If you don’t have an iPhone / iPad, here’s a video of the test in action:
As you can see, frame-rates on the iPad vary from "unacceptably bad" at fullscreen to "okay, I guess" at the relatively tiny resolution of 250x250.
And notice how much snappier the animation becomes when we stop clearing the canvas between frames! Canvas was originally designed to generate static images, not animations, and the standard canvas clearing method (calling
ctx.clearRect(0, 0, width, height)) appears to be quite expensive.
I did experiment with alternative clearing methods, including:
- Creating an empty canvas on page load, grabbing its contents with
getImageDataand sending it to the canvas on the page with
- Replacing the canvas element with a new one each frame.
- Forcing a refresh of the canvas element by resetting it’s width every frame (Using
canvas.width = canvas.width+0)
All of which you can experiment with in the above demo. None of these, however, improved clearing performance significantly.
As a result of these tests, we’ve decided to ditch canvas as a viable option for fullscreen games on iOS.
That only leaves one option for us: CSS transitions.