Monday, October 24, 2011

Adventures in HTML5: Bouncy Bar Chart

Today I'm sharing a bar chart I recently built in JavaScript using HTML5 canvas. You can see a demo here (simple bar chart, multiple bar charts) and download the code here. Below I walk through the steps I went through to create this.

I'm learning JavaScript right now, and I recently shared my first JavaScript program of any consequence, a doomsday counter. This is my second JavaScript program. I time-boxed this experiment to one day (and spent a few additional hours afterward making the code pretty for this post).I was pleasantly surprised to see how much I was able to accomplish in one day. As I get more comfortable with JavaScript, I'm starting to look past the rough edge in the language and appreciate its good points. I'm sure my code technique still reflects a beginner, but as I learn more from Pluralsight courses and books like JavaScript: The Good Parts and use tools like jslint I'm getting there.

Inspiration: Jelly Charts

My inspiration for this bar chart control is a very cool online chart demo done in Silverlight I found a few years back called RichardZ's Jelly Charts. They are remarkable--highly animated and responsive, they render on the screen with a bouncy, cascading effect that is mesmerizing and addictive. Unfortunately as far as I cacn determine no source or binaries or available, but now that I'm going deep on HTML5 this provided an opportunity to create something similar. So that was my mission, to essentially match Jelly Bar in HTML5 canvas and JavaScript.

Step 1: Basic Canvas Drawing

The first thing I needed to do was get acquainted with HTML5 canvas and basic operations like drawing a line or a rectangle. The HTML5 canvas feature allows you to declare one or more elements in your HTML page, which JavaScript can then render graphics to using methods like fillRect to draw a rectangle. A good introduction to the basics of canvas and other HTML5 features can be found on

Step 2: Calculations and Drawing

With some basic canvas skills it was time to write the code to do the math and draw it. Plotting axis lines, tick marks, and bars. Straightforward, but a lot of work to allow the caller flexibility of canvas size and range of values.

Step 3: Gradients & Text on Canvas

As I got the basic elements drawn it was time to master more subtleties including gradient colors and text on canvas and font control. It was easy enough to find online examples of what I needed, though in the back of my head I was wondering if I shouldn't be leveraging CSS for some of this--I need to learn more about whether there is a way to apply CSS to canvas elements. For now, it's done in the JavaScript--but the ultimate result does allow the caller to control things like colors and fonts. I also added ability to specify a chart title, column titles for the X-axis, and value labels for the bars.

Step 4: Dynamic Resizing

A chart control isn't much use unless the caller can control its size as well as the web user being able to resize their browser window. Although my work so far had not made any assumptions about canvas size or value ranges, more code would be needed to dynamically redraw the chart if the browser window was resized. I found I could use code like this in my HTML page to resize the canvas in response to a browser resize. Although this sort of worked, the browser would sometimes add scroll bars; to counter this I ended up reloading the page on resize and then dynamically sizing the canvas and drawing the chart. Not ideal, but it does work.

Step 5: Fluid Bar Animation

One of the most attractive things about the Jelly Charts are their animation. The Jelly Bar has a vertical bounce effect where the bar is drawn up, higher than its resting height, and then bounces down into position. It also draws the bars left to right with a slight delay so that there is a cascading effect horizontally. While I didn't quite equal this effect in my one-day experiment, I was able to approximate it. I used a timer to draw the bar up to an exagerrated height, and then to lower it to its correct height.

Step 6: Object Parameters & Multiple Charts

In my initial prototyping I just had a sea of global and local variables; to make the chart something useful it would need to be tidied up so that it could be easily called, controlled by the caller, and allow for multiple charts. Using JavaScript objects took care of that problem. The caller registers a chart by calling BarChart(chart) in the JavaScript library, where chart is a Chart object that includes the canvas Id to render the chart to. Charts tend to have a lot of parameters, so intelligent defaulting of chart values was an important part of this work.

Step 7: Multiple Series and Customization

If we're supporting mutliple charts, we might as well support multiple series within a bar chart too. Now Chart.bars is an array of series, where each series is an array of bar objects. I also added customization of colors, and the ability to have a transparent background in case you wanted an iamge or some other background controlled by the HTML/CSS (2-chart demo).

Step 8: Hover & Highlighting

The Jelly Bar allows you to hover over a bar and highlight it in a different color, and I also wanted to create this behavior in my edition. This gave me an opportunity to learn about mouse events. I added a mousemove event listener for the canvas of each registered chart, and also maintain a "hit list" of rendered bars. In response to a mouse move, I scan the mouse coordinates against the hit list to see if the mouse is over a bar. If we have moved over a bar (or off a bar we were previously over), the bar is either highlighted in a different color or restored respectively.

Well, there we are--not bad for a day's work. It seems to work well across mainstream browsers as well as tablets and phones though I can see I need to do some thinking about adjusting the rendering animation speed for various devices and display sizes. I had fun doing this and am finding a promising increase in velocity as I continue to work on my mastery of JavaScript and all things HTML5. Links to the code and demos are at top.


Fred said...

Nice article, good work.

Anonymous said...

jolly good

Anonymous said...

very cool indeed! Thanks Peter