This is the first in a series of tutorials on how to do d3.js on mobile devices - subscribe to the RSS feed or follow me on twitter to tag along!
One thing that people tend to forget in today's HTML5-ed world is how extremely fast Flash actually was and still is. Constructing complex chains of tweened animations and having them run in real-time was absolutely doable and represented a major advantage compared to other in-browser graphics frameworks such as Java. And, as wonderful as HTML5 is, we're still at least a couple of years behind in that regard. HTML5 is not the magic bullet that saves your device from high battery or CPU consumption and, yes, you can create memory leaks in Javascript and crash your browser.
I had to learn the restrictions of HTML5 with the revamp of the OECD's Better Life Index. In this blog post I will describe some of the approaches and solutions that we used to get the HTML5 version of that visualization on equal footing with its Flash ancestor.
The Better Life Index (BLI)
The OECD Better Life Index (BLI) is an appealing, web-based visualization of various quality-of-life indicators for a set of 36 countries. Personal preferences can be set for each of these indicators to get a personal ranking of countries. You could, for example, express your desire for high 'Safety' while downranking 'Environment' to find that Canada really is the perfect country for you.
Every time these settings are changed, the flowers representing the countries adjust by changing their petals' colors and sizes (each petal represents one quality-of-life indicator). Moritz Stefaner didn't hold back when designing the Flash original and crammed in as many animations as possible:

Flower animations in the (Flash) Better Life Index (click to see the animation).
Every change in settings potentially leads to changes in a flower's petals' colors, orientations, sizes and a position change for the flower and its label. With 36 flowers with 11 petals each on-screen you can imagine how this might lead to problems, performance-wise.
So, how do you re-create something like that without your comfy Flash tweens and animations?
Minimize overhead, go as low-level as possible
One initial decision we had to make was between rendering to SVG or Canvas (WebGL is very promising but still lacks support). Both graphics technologies are well-supported in modern browsers but come with very different qualities: SVG is a vector-based format that represents basic geometric bodies as DOM-elements and gives you all the nice things that DOM-elements have such as event handlers tied to objects. Canvas is, as the name implies, only a blank slate bitmap with several helper functions for pixel-based drawing - no more, no less. Oh, and all this event handling: yeah, you have to write that yourself.
Actually comparing the performance of SVG and Canvas is tough, as it depends on both the size of the drawing area (that adds to drawing complexity in Canvas) as well as the number of objects (that adds to DOM-overhead for SVG). So simply displaying a single bouncing cube might not be enough. Microsoft (yes, the Internet Explorer Microsoft) has a great comparison write-up between the two technologies.
In a nutshell, your choice between SVG and Canvas depends on the drawing area and the number of graphical objects:
SVG/Canvas | Canvas | |
SVG | probably Canvas, but seriously: you're screwed |
With our close to 500 objects (flowers, petals, stems, labels) and an almost full-screen visualization we were right in the middle of screwed-up country. Fortunately, we managed to shift the problem a little bit towards the top by splitting one large Canvas into many small ones (see below). But in any case: if in doubt and performance is important, Canvas always means less overhead and more control over the results, so we went with Canvas.
In the same vein, we initially used Paper.js for drawing. Paper.js is a fantastic Canvas library for creating complex vector-based graphics. It gets you pleasantries such as a scene graph or being able to tie event handlers to Canvas objects. But all of that comes at a price, as Paper.js creates - very similar to SVG - an additional amount of overhead for each graphical object. So, while Paper.js let us quickly recreate the visualization in HTML5, the result wasn't very fast. In the end, we dropped Paper.js and used native (=pure Javascript) Canvas-drawing for everything.
The more elements, the better
Most performance-downsides of Canvas elements come from redrawing them. As Canvas is more or less a dynamic bitmap, every time it is redrawn your visualization's performance takes a hit. This heavily depends on what your drawing function looks like: it even makes a difference how you clean your Canvas before drawing something new.
Another trick is to make sure that you only draw as little as possible: if only the upper-right corner of your Canvas needs an update, make sure that only that part is cleaned and redrawn and not the whole thing ('dirty rectangles' are one way from computer graphics to keep track of that).
You can also minimize drawing time by having as little calculations as possible in the your drawing routine (see below).
But important for us here and just as you would expect, the performance hit correlates with the size of the Canvas element: redrawing a screen-filling Canvas takes much longer than redrawing a tiny 10x10 pixel element or even several hundred of them. So it always makes sense to split up your graphical objects into as many smaller versions as possible (except when you're using a library that creates additional overhead for every new object - which brings us back to going as low-level as possible). While we started out with a single Canvas that contained all flowers and their labels, in the end we had one Canvas element per flower (as the middle ground between giving each flower petal its own Canvas) and each flower label as a separate div element containing text:

Splitting up larger elements into smaller one usually gives you performance benefits. Initially, the BLI had all graphical elements on a single Canvas (left), but we ended up with one Canvas per flower (right).