Anxious Silence

HTML 5 Graph Slider

Posted April 27th, 2010 23:17 by Bob

HTML5 Graph Slider_1272407446781

Been having a play with HTML5, very excited by the new semantics and especially keen on the new canvas tag. Aware that it’s not going to be supported everywhere in the immediate future but it’s a great step in the right direction. I don’t think it’s going to be the immediate flash killer some have made it out to be anytime soon (I love flash and AS and have no desire to see them go), but it can certainly work as a good alternative to flash for simple animation and interactivity. Once the decent JS frameworks add more functionality to support it it’s going to make life a lot more interesting.

I’ve put together a couple of experimental demos with HTML5 this week, this is the first. It’s a dynamic graph viewer. It can accept data via javascript and update the graphs on the fly. The data in question in the demo is supplied by the sliders but it can come from anywhere you like. I’ve kept the graphics basic for the sake of the demo.

View Demo.

I’ve not written any sort of tutorial/code article before, so bear with me, feel free to just download the source.

I’ve used jQuery and jQuery UI in the name of agile development. The jQuery ui for the sliders and a couple of jQuery statements to get measurements and deal with events, these could be easily swapped out for alternative frameworks or more verbose standard javascript.

The HTML

View the source of the demo for the full HTML, I’ll just include the pertinent parts here:

  1. <div id="Graphs">
  2.         <canvas width="200" height="150" id="Graph1"></canvas>
  3.         <canvas width="200" height="150" id="Graph2"></canvas>
  4. </div>
  5. <div id="Controls">
  6.         <div id="Slider1"></div>
  7.         <div id="Slider2"></div>
  8.         <div id="Slider3"></div>
  9.         <div id="Slider4"></div>
  10. </div>

This sets up two canvases, one for each graph, I’ve named them the imaginative ‘Graph1′ and ‘Graph2′. The controls div contains four divs to be converted to jQuery UI sliders (one for each point / bar on the graphs).

The Javascript

First off we set up a couple of global variables:

  1. var graphPadding = 10;
  2. var colours = new Array("rgb(200,0,0)","rgb(0,200,0)","rgb(0,0,200)","rgb(0,200,200)");

graphPadding is just a number to use for spacing items of the graphs out. I’ve just set a single number to use for all margins, spacing, etc to keep things simple. colours is an array of colour codes, one for each of the graph points.

Next we initialise with the nice jQuery document.ready function:

  1. jQuery(document).ready(function($){
  2.  
  3.         /* Generate Nice jQuery UI Sliders */
  4.         $(‘#Slider1, #Slider2, #Slider3, #Slider4′).slider({
  5.                 slide: function(event,ui){drawGraphs();}
  6.         });
  7.  
  8.         /* Set some random initial values for the sliders */
  9.         $(‘#Slider1, #Slider2, #Slider3, #Slider4′).each(
  10.                 function(){
  11.                         $(this).slider(‘value’,Math.random() * 100);
  12.                 }
  13.         );
  14.  
  15.         drawGraphs();
  16.  
  17. });

The first command sets up the jQuery UI sliders including giving them the appropriate event handler to redraw the graph whenever any of them are changed. The second command just sets each slider to a random value. Next we call drawGraphs to draw their initial state.

Now we have the main graph drawing function, this is set up to draw both graphs in one go.

  1. function drawGraphs(){
  2.         /* Get the canvas dimensions, we know they are both the same so we shall be lazy and only check once */
  3.         var cHeight = parseInt($(‘#Graph1′).height());
  4.         var cWidth = parseInt($(‘#Graph1′).width());
  5.  
  6.         /* Clear the Canvases */
  7.         clearCanvas($(‘#Graph1′));
  8.         clearCanvas($(‘#Graph2′));

First we get the canvas dimensions, these could be stored as constants/globals somewhere or hard coded but I like the flexibility of checking on the fly. Really we should check each one individually and split the graph drawing into two functions but it’s a demo and I don’t care. Then we clear each canvas to start drawing on it using a function which will be defined below.

  1. /* Graph 1  - The line graph */
  2.         // Get Context
  3.         var canvas = document.getElementById("Graph1");
  4.         var ctx = canvas.getContext("2d");
  5.  
  6.         // Set Stroke Style
  7.         ctx.strokeStyle = "rgb(0,0,0)";

Prepare to draw the first graph by getting a reference to the appropriate canvas then calling getContext on it. Then we set the stroke style to black.

  1. // Draw Axis
  2.         ctx.beginPath();
  3.         ctx.moveTo(graphPadding, graphPadding);
  4.         ctx.lineTo(graphPadding,cHeight - graphPadding);
  5.         ctx.lineTo(cWidth - graphPadding, cHeight - graphPadding);
  6.         ctx.stroke();
  7.         ctx.closePath();

Draw the axis, a simple case of drawing two straight lines. We use a combination of the canvas dimensions and the graphPadding global to work out the positions.

  1. // Display a point for each slider, spaced equally
  2.         var availableSpace = cWidth - (graphPadding * 4);
  3.         var horizSpace = availableSpace / 3;
  4.         var vertSpace = cHeight - (graphPadding * 4);

Work out how much space we actually have to draw the points in. The first point is two sets of graphPadding from the left and the last is two from the right hence the * 4. Same applies vertically.

  1. // Create an array of y points
  2.         var points = new Array();
  3.         for(var i = 0;i < 4;i++){
  4.                 // Get Ypos
  5.                 var yPercent  = ($(‘#Slider’ + (i + 1)).slider(‘value’) - 100) * -1;
  6.                 var yPos = (vertSpace * (yPercent / 100) + (graphPadding * 2));
  7.                 points.push(yPos);
  8.         }

The points will be equally spaced horizontally so we just need to get their vertical position. Loop through the sliders, get the value for each one (0 – 100), work out the percentage of the available vertical space and add it to the points array.

  1. // Draw Lines
  2.         var xPos = graphPadding * 2;
  3.         ctx.beginPath();
  4.         for(i = 0;i < 4;i++){
  5.                 if(i == 0){
  6.                         ctx.moveTo(xPos, points[i]);
  7.                 }else{
  8.                         ctx.lineTo(xPos, points[i]);
  9.                 }
  10.                 xPos += horizSpace;
  11.         }
  12.         ctx.stroke();
  13.         ctx.closePath();

Draw the graph lines. We separate the line drawing and point drawing as when we draw a circle it calls closePath which knackers up our lines (there’s probably a better way). To draw the lines we loop through the points and draw a line between each one.

  1. // Draw Dots
  2.         var xPos = graphPadding * 2;
  3.         for(i = 0;i < 4;i++){
  4.                 drawCircle(ctx, xPos, points[i], 4, colours[i]);
  5.                 xPos += horizSpace;
  6.         }

To draw the points we just loop through the points array again, drawing a circle at each one, again the horizontal position of each point is fixed.

I’ll cut out most of the code for Graph 2 as it’s identical. The part of interest is:

  1. // Work out width of each bar
  2.         var availableWidth = cWidth - (graphPadding * 6);
  3.         var barWidth = availableWidth / 4;
  4.         var maxHeight = cHeight - (graphPadding * 3);
  5.  
  6.         // Draw bars
  7.         var xPos = graphPadding * 2;
  8.         for(i = 0;i < 4;i++){
  9.                 // Work out height
  10.                 var h = maxHeight * ($(‘#Slider’ + (i + 1)).slider(‘value’) / 100);
  11.                 var yPos = cHeight - h - (graphPadding * 2);
  12.                 ctx.fillStyle = colours[i];
  13.                 ctx.fillRect(xPos, yPos, barWidth, h);
  14.  
  15.                 xPos += barWidth + graphPadding;
  16.  
  17.         }

Here we work out the available space for the bars by subtracting the appropriate number of graphPaddings from the total available space then dividing the result by the number of bars. We work out the max height of each bar by deleting 4 * graphPadding from the total available height.

Then we loop through the sliders, get the percentage value from each one and set it’s bar to the given percentage of the total height.

That’s pretty much it. I’ve used two additional helper functions which are based on those found at the Mozilla Canvas tutorial, they shouldn’t need any explanation:

  1. /**
  2.  * clearCanvas
  3.  * Clears a canvas, by setting it’s width.
  4.  */
  5. function clearCanvas(element){
  6.         $(element).attr(‘width’,$(element).attr(‘width’));
  7. }
  8.  
  9. /**
  10.  * drawCircle
  11.  * Draws a circle
  12.  */
  13. function drawCircle(ctx, x, y, radius, colour){
  14.         ctx.fillStyle = colour;
  15.         ctx.beginPath();
  16.     ctx.arc(x, y, radius,0,Math.PI*2,true); // Outer circle
  17.     ctx.fill();
  18.  
  19. }

So, there you go. Dynamic graphs without flash or server side graphics libraries. These could of course be achieved pretty much entirely with CSS and JS but it’s been a nice intro to HTML5 and the canvas tag.

I’ve not given this a huge amount of testing (or thought) as really for my own entertainment but hope it’s of interest.

14 Responses to “HTML 5 Graph Slider”

  1. kredyty bez bik Did utter:

    Thanks.

  2. HTML5 Canvas Graphing Solutions Every Web Developers Must Know | Web Designer Aid Did utter:

    [...] 6. HTML5 Graph Slider [...]

  3. Tampa Web Design Did utter:

    Nice one Its can certainly work as a good alternative to flash for simple animation and interactivity..

  4. 18个基于 HTML 5 Canvas 开发的图表库 « Untitled (未名空间) Did utter:

    [...] Building HTML5 Canvas Bar Graph使用HTML5 Canvas元素和Javascript绘制条形图。6. HTML5 Graph Slider一个动态图形查看器,可通过JavaScript接收数据并即时更新到图表中。7. [...]

  5. lx's blog » Blog Archive » 推荐18个基于 HTML5 Canvas 开发的图表库 Did utter:

    [...] 6. HTML5 Graph Slider [...]

  6. HTML 5可以做五件事情 超出你的想象——4. 以更直观的方式让数据可视化呈现 | 教育技术支持 Did utter:

    [...] 2.http://www.anxioussilence.co.uk/blog/2010/04/27/html-5-graph-slider/ [...]

  7. 推荐18个基于 HTML5 Canvas 开发的图表库 « ARM9 & Embedded System Did utter:

    [...] 6. HTML5 Graph Slider [...]

  8. 推荐18个基于 HTML5 Canvas 开发的图表库 | uedchina 专注于用户体验设计 Did utter:

    [...] 6. HTML5 Graph Slider [...]

  9. 推荐18个基于 HTML5 Canvas 开发的图表库 | 扑街网! www.PutSky.com Did utter:

    [...] 6.HTML5 Graph Slider [...]

  10. (转)推荐18个基于 HTML5 Canvas 开发的图表库 | 蓝轩 Did utter:

    [...] 6. HTML5 Graph Slider [...]

  11. 推荐18个基于 HTML5 Canvas 开发的图表库 | 积累吧 Did utter:

    [...] 6. HTML5 Graph Slider [...]

  12. 桔子小窝 » HTML5 Canvas Graphing Solutions Every Web Developers Must Know Did utter:

    [...] 6. HTML5 Graph Slider [...]

  13. 推荐18个基于 HTML5 Canvas 开发的图表库 | 田淏予博客 Did utter:

    [...] 6. HTML5 Graph Slider [...]

  14. 推荐18个基于 HTML5 Canvas 开发的图表库 | 如果人生是一场战争,那你最大的敌人其实是自己...工作和生活的劳逸结合... Did utter:

    [...] 6. HTML5 Graph Slider [...]

Leave a Reply