Skip to Content

A few months back, I did a series of posts that used SQL Anywhere to create SVG graphs that were displayed in the browser. Today I would like to explore another browser technology for creating graphics, the HTML canvas tag . While the canvas tag is part of the developing <a href=””>HTML5 spec, it has already been implemented in most browsers (with the notable exception being Internet Explorer). The main differences between SVG and Canvas are:

    1. SVG uses vector graphics , Canvas uses raster graphics . This means that SVG is better when the scale is unknown, or when you need the ability to manipulate specific parts of the image. Canvas is better with a fixed size, and when you want to paint arbitrary pixels.
    2. SVG is described in a declarative, XML markup language. Canvas is created procedurally in JavaScript.

For the series on SVG, we created the declarative SVG markup on the server and then displayed it statically on the client. For this demonstration of the canvas, we will be creating a dynamic, animated graph that polls the server for values. In the end, the graph will look like a scrolling version of:

The HTML canvas is used by first declaring a canvas tags in the HTML source. The developer then uses a JavaScript API to paint pixels on the image. It may sounds somewhat limiting, but it can be quite powerful. As an example the entire Bespin front-end is rendered entirely in the canvas. Or, for a more fun example, here is a demonstration of using the HTML canvas for a Doom -like ray-caster written entirely in JavaScript.

The goal of this demo is to create a scrolling performance graph that displays some arbitrary value in the SQL Anywhere server.  The first thing we need is to create a couple of services. The first will return the HTML page containing the canvas. The second is the procedure that we will poll to get the graph values.


The getGraphData service in turn calls the sp_getGraphData procedure. We will design our JavaScript such that it expects back an arbitrary piece of JSON containing up to three values to graph simultaneously. For example, a valid object would be:

{ cpu         : 10,
  memory      : 15,
  dirty_pages : 5 }

For our first example, we will use something simple and meaningless (a random number between 0 and 100):

CREATE PROCEDURE "sp_getGraphData"()
  SELECT '{rand:' || (RAND() * 100) || '}';

The JavaScript that creates the graph is quite simple, and is shown below. After the HTML is loaded, the getData() function is called. getData makes immediate Ajax request to the getGraphData service, and gets a JSON object in response. The Ajax callback function takes the response and adds it to moving queue of data to graph. It then iterates through the queue, updating the canvas to display the new graph. Once the graph is drawn, it sleeps for a configurable amount of time and then polls again.

// ***** START OF CONFIG PARAMS ***** //
var WIDTH = 300; // also must change HTML canvas width
var HEIGHT= 50; // also must change HTML cnavas height
var MAX = 59;
var MIN = 0;
// ***** END OF CONFIG PARAMS ***** //
var norm = HEIGHT/(MAX - MIN);
var queue = [];
var colour_map = ["rgb(0,0,255)", "rgb(0,255,0)", "rgb(255,0,0)"];
function getData() {
 jQuery.getJSON( 'getGraphData', null, function (data) {
 // Get reference to the canvas
 var canvas = document.getElementById('canvasGraph');
 var ctx, colour, pos, index, item;
 // Add new value onto our "queue"
 if (queue.push(data) > WIDTH) {
 // if we have more than WIDTH elements, delete the oldest
 delete queue[queue.length - (WIDTH + 1)]
 if (queue.length > 2) {
 if (canvas.getContext){
 ctx = canvas.getContext('2d');
 ctx.clearRect(0,0,WIDTH,HEIGHT) // Clear the drawing area
 colour = 0; // Set first colour
 // Iterate through all the items in the data object
 // and draw the graph line with normalization
 for (item in queue[queue.length - 1])
 ctx.strokeStyle = colour_map[colour];
 pos = WIDTH;
 index = queue.length - 1;
 ctx.moveTo(pos, HEIGHT-((queue[index][item]-MIN)*norm));
 while(pos > 1 && index > 1)
 pos = pos - 1;
 index = index - 1;
 ctx.lineTo(pos, HEIGHT-((queue[index][item]-MIN)*norm));
 // Wait for SAMPLE_RATE_IN_MS, then get more data
 setTimeout(getData, SAMPLE_RATE_IN_MS);

To use this graph for something meaningful you simply need to do two things:

  1. Define the sp_getGraphData() to return some meaningful data
  2. Set the WIDTH, HEIGHT, SAMPLE_RATE_IN_MS, MAX, and MIN constants

For example, to create a graph of the current second value (MIN=0, MAX=59) on a 100×400 graph, with a 1 second resolution, we have to: (view full SQL code)

1. Create the appropriate sp_getGraphData()

CREATE PROCEDURE "sp_getGraphData"()
  SELECT '{second:' || (SELECT SECOND(NOW())) || '}';

2. Set the proper config settings in the JavaScript

// ***** START OF CONFIG PARAMS ***** //
var WIDTH = 400; // also must change HTML canvas width
var HEIGHT= 100; // also must change HTML cnavas height
var SAMPLE_RATE_IN_MS = 1000;
var MAX = 59;
var MIN = 0;
// ***** END OF CONFIG PARAMS ***** //

The result (as you would expect), is a sawtooth graph:

If we change the resolution to 50 ms, the result is:

Now it appears as a stepped sawtooth. This makes sense since we are sampling many more times a second.

The lowest poll rate that I tried was 10ms, and neither Chrome nor Firefox broke a sweat keeping up with the graph. There are a number of limitations with this simplistic graph (notably no scale or labels on the output), but it is easily expandable.

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply