AwesomeCo is doing a lot of work on the website, and senior management
would like to see a graph of the web stats. The back-end programmers
will be able to get the data in real time, but first they’d like
to see whether you can come up with a way to display the graph in the
browser, so they’ve provided you with some test data. Our goal is to
transform that test data into something that resembles Figure 6.2, on
the following page.
There are lots of ways to draw graphs on a web page. Developers use
Flash for graphs all the time, but that has the limitation of not working
on some mobile devices like the iPad or iPhone. There are server-side
solutions that work well, but those might be too processor-intensive if
you’re working with real-time data. A standards-based client-side solution
like the canvas is a great option as long as we’re careful to ensure it
works in older browsers. You’ve already seen how to draw squares, but
drawing something complex requires a lot more JavaScript. We need a
graphing library to help us along.
The fact that HTML5 isn’t available everywhere yet hasn’t stopped the
developers of the RGraph library.5 RGraph makes it ridiculously simple
to draw graphs using the HTML5 canvas. It’s a pure JavaScript solution,
though, so it won’t work for those user agents that don’t have
JavaScript available, but then again, neither will the canvas. Here’s the
code for a very simple bar graph:
<canvas width=”500″ height=”250″ id=”test”>[no canvas support]</canvas>
<script type=”text/javascript” charset=”utf-8″>
var bar = new RGraph.BarC’test’, [50,25,15,10]);
bar.SetC’chart.gutter’, 50);
bar.Set(‘chart.colors’, [‘red’]) ;
bar.SetC’chart.title’, “A bar graph of my favorite pies”);
bar.SetC’chart.labels’, [“Banana Creme”, “Pumpkin”, “Apple”, “Cherry”]);
bar.DrawC) ;
</script>
draws the graph on the canvas for us.
Describing Data with HTML
We could hard-code the values for the browser statistics in the Java-
Script code, but then only users with JavaScript would be able to see
the values. Instead, let’s put the data right on the page as text. We can
read the data with JavaScript and feed it to the graphing library later.
<div id=”graph_data”>
<hl>Browser share for this site</hl>
<ul>
<li>
<p data-name=”Safari 4″ data-percent=”15″>
Safari 4 – 15%
</p>
</li>
<li>
<p data-name=”Internet Explorer” data-percent=”55″>
Internet Explorer – 55%
</p>
</li>
<li>
<p data-name=”Firefox” data-percent=”14″>
Firefox – 14%
</p>
</li><li>
<p data-name=”Google Chrome” data-percent=”16″>
Google Chrome – 16%
</p>
</li>
</ul>
</div>
We’re using the HTML5 data attributes to store the browser names and
the percentages. Although we have that information in the text, it’s
so much easier to work with programmatically since we won’t have to
parse strings.
If you open up the page in your browser or just look at Figure 6.3,
you’ll see that the graph data is nicely displayed and readable even
without the graph. This will be your fallback content for mobile devices
and other users where either the canvas element or JavaScript is not
available.
Now, let’s turn this markup into a graph.
Turning Our HTML into a Bar Graph
We’re going to use a bar graph, so we’ll need to require both the RGraph
Bar graph library as well as the main RGraph library. We’ll also use
j Query to grab the data out of the document. In the head section of the
HTML page, we need to load the libraries we need.
<script type=”text/javascript”
charset= “utf-8″
src=”http://ajax.googleapis.com/ajax/1ibs/jquery/1.4.2/jquery.min.js”>
</scri pt>
<script src=”javascri pts/RCraph. common, js” ></script>
<script src=”javascripts/RCraph.bar.js” ></script>
To build the graph, we need to grab the graph’s title, the labels, and
the data from the HTML document and pass it to the RGraph library.
RGraph takes in arrays for both the labels and the data. We can use
j Query to quickly build those arrays.
Une l function canvasGraph(){
var title = $(‘#graph_data hi’) .textO ;
var labels = $C”#graph_data>ul>li>p[data-name]”).map(function(){
5 return $(this),attr(“data-name”);
} ) ;
var percents = $C”#graph_data>ul>li>p[data-percent]”).map(function(){
return parselnt($(this).attr(“data-percent”)) ;
io });
var bar = new RGraph.Bar(‘browsers’, percents);
bar.SetC ‘chart.gutter’ , 50);
bar.Set(‘chart.colors’, [ ‘red’]) ;
15 bar. Set C ‘chart, title’ , title);
bar.Set( ‘chart.labels ‘ , labels);
bar.DrawO ;
}
First, on line 2, we grab the text for the header. Then, on line 4, we select
all the elements that have the data-name attribute. We use jQuery’s map
function to turn the values from those elements into an array.
We use that same logic again on line 8 to grab an array of the percentages.
With the data collected, RGraph has no trouble drawing our graph.
Displaying Alternative Content
In Section 14, Describing Data with HTML, on page 120, I could have
placed the graph between the starting and ending canvas tags. This would hide these elements on browsers that support the canvas while
displaying them to browsers that don’t. However, the content would
still be hidden if the user’s browser supports the canvas element but
the user has disabled JavaScript.
We simply leave the data outside the canvas and then hide it with
jQuery once we’ve checked that the canvas exists.
var canvas = document.getElementByld(‘browsers’);
if (canvas.getContext){
$C’#graph_data’) .hideO ;
canvasGraphO ;
}
Falling Back
When building this solution, we already covered fallbacks for accessibility
and lack of JavaScript, but we can create an alternative graph for
people who don’t have canvas support but can use JavaScript.
There are a ton of graphing libraries out there, but each one has its
own way of grabbing data. Bar graphs are just rectangles with specific
heights, and we have all the data on the page we need to construct this
graph by hand.
Line l function divGraph(barColor, textColor, width, spacer, lblHeight){
$(‘#graph_data ul’).hide();
var container = $C’#graph_data”) ;
5 container.css( {
“display” : “block”,
“position” : “relative”,
“height”: “300px”}
);
$ C”#graph_data>ul>li>p”).each(function(i){
var bar = $(“<div>” + $(this) .attrC’data-percent”) + “%</div>”) ;
var label = $(“<div>” + $(this) ,attr(“data-name”) + “</ch’v>”);
var commonCSS = {
“width”: width + “px”,
“position” : “absolute”,
“left” : i * (width + spacer) + “px”};
var barCSS = {
“background-color” : barColor,
“color” : textColor,
“bottom” : lblHeight + “px”,
25 “height” : $(this) .attr(“data-percent”) + “%”
};
var labelCSS = {“bottom” : “0”, “text-align” : “center”};
bar.cssC $.extend(barCSS, commonCSS) );
30 label.css( $. extend (label CSS, commonCSS) );
container.append(bar);
container.append(label);
});
}
On line 2, we hide the unordered list so that the text values are hidden.
We then grab the element containing the graph data and apply some
basic CSS styles. We set the positioning of the element to relative on 6,
which will let us absolutely position our bar graphs and labels within
this container.
Then we loop over the paragraphs in the bulleted list (line 11) and create
the bars. Each iteration over the labels creates two div elements, one for
the bar itself and another for the label, which we position below it. So,
with just a little bit of math and some j Query, we are able to re-create
the graph. Although it doesn’t look exactly the same, it’s close enough
to prove the concept.
We then just need to hook it into our canvas detection, like this:
if (canvas.getContext){
S(‘#graph_data’).h i de();
canvasGraphO;
}
else{
divGraph(“#f 00”, “#fff”, 140, 10, 20);
}
You can see the fallback version in Figure 6.4. With a combination
of JavaScript, HTML, and CSS, we’ve provided a client-side bar graph
and statistical information about browser usage to any platform that
requires it. Using the canvas has an additional benefit—it got us to
start thinking about a fallback solution from the beginning, rather than
trying to wedge something in later. That’s really good for accessibility.
This is one of the most accessible and versatile methods of graphing
data available. You can easily create the visual representation as well
as a text-based alternative. This way, everyone can use the important
data you’re sharing.
The Future
Now that you know a little about how the canvas works, you can start
thinking of other ways you might use it. You could use it to create
a game, create a user interface for a media player, or use it to build
a better image gallery. All you need to start painting is a little bit of
JavaScript and a little bit of imagination.
Right now, Flash has an advantage over the canvas because it has
wider support, but as HTML5 picks up and the canvas is available to a
wider audience, more developers will embrace it for simple 2D graphics
in the browser. The canvas doesn’t require any additional plug-ins
and uses less CPU than Flash, especially on Linux and OS X. Finally,
the canvas provides you with a mechanism to do 2D graphics in environments
where Flash isn’t available. As more platforms support the
canvas, you can expect the speed and features to improve, and you’ll
see more developer tools and libraries appear to help you build amazing
things.
But it doesn’t stop with 2D graphics. The canvas specification will eventually
support 3D graphics as well, and browser manufacturers are
implementing hardware acceleration. The canvas will make it possible
to create intriguing user interfaces and engaging games using only
JavaScript.