CANVAS GRAPHICS
Canvas Graphics Using CvsGraphCtx
The ability to create arbitrary 2D graphic images under script control has lacked a cross browser solution. The canvas element was designed to provide this JavaScript programmable graphics capability. It is part of the HTML 5 proposal.
The canvas element has native support in all the major browsers, Firefox, Safari, Opera etc. Internet Explorer lacks native support for the canvas element, but an excellent canvas emulator excanvas translates canvas methods into IE's VML graphics.
CvsGraphCtx, a User Friendly Canvas Graphics Context
The canvas element's programming interface still requires a lot of JavaScript code to produce useful graphics. There is no native support for user coordinate system, so all drawing coordinates must be scaled to map onto the pixel dimensions of the canvas. Nor is there any support for drawing in layers, all drawing is flattened onto the canvas background, animation thus requires redrawing the whole scene each frame. The CvsGraphCtx canvas graphics context provides a user friendly graphics command set, addressing these issues.
CvsGraphCtx is programmed using only the commands common to the excanvas emulator and HTML5 canvas methods. The official version of excanvas, Rev 3, when used with IE8, has some trouble with image manipulation. This problem has been fixed by patches written by Tommy Maintz, his version excanvas-modified.js, allows all the graphics written with CvsGraphCtx to produce similar out in IE6, IE7, IE8, Firefox, Chrome and Safari.
The main features of the CvsGraphCtx library are:
- Viewport and World Coordinates - data may to be plotted in the data's original units, removing the need to scale all values to canvas pixels. An arbitrary viewport within the canvas (or the whole canvas) can be used to define the coordinate system. Multiple graphics contexts each with its own coordinate system may exist on a single canvas.
- Text - labels and other text may be positioned in world coordinates with all 9 vertical and horizontal alignment options, arbitrarily rotated and with variable font size. The cross browser text capability is provided by canvastext library written by Jim Studt. The stroke text is rendered directly into the canvas with all other drawing.
- Images - jpg, gif and png images may be positioned and scaled in world coordinates with all 9 vertical and horizontal alignment options and arbitrarily rotated.
- Layers - multiple independent transparent canvas surfaces can be overlayed. These can be drawn onto and erased without interfering with the drawing on other layers.
- Shapes - higher level drawing function have been added to facilitate drawing arrows, circles, triangles and squares. Even more complex polygons and curved shapes are supported.
- Dashed or Dotted lines - There is no native support for dashed or dotted lines in canvas element methods, CvsGraphCtx adds these line styles.
Using CvsGraphCtx.
Firstly, download the four JavaScript files required for CvsGraphCtx:
cvsGraphCtx1v03.js,
excanvas-modified.js,
canvastext.js,
rgbaColor.js.
These should be placed in the same directory as the web page html file. Then add the following lines to the web page HTML file header:
<!--[if IE]><script type="text/javascript" src="excanvas-modified.js"></script><![endif]--> <script type="text/javascript" src="cvsGraphCtx1v03.js"></script> <script type="text/javascript" src="canvastext.js"></script> <script type="text/javascript" src="rgbaColor.js"></script>
Within the body of the web page, the canvas is inserted as a normal HTML element. The only canvas attribute required is a unique id. The width and height attributes may specify the size, or the CSS styling is used to set the canvas dimensions.
The required HTML code is:
<canvas id="canvasID" width="500" height="300"></canvas>
The CvsGraphCtx Drawing Context
Each graphics context is an instance of the CvsGraphCtx object, with its own set of properties such as viewport dimensions, world coordinate system scaling factors, pen colour and so on. A single CvsGraphCtx may be re-used, a new viewport can be defined to draw another graph, perhaps over the top of a previous graph or along side, and so on. Alternatively, multiple CvsGraphCtx instances may exist simultaneously on the same canvas, each having its own property set. Drawing calls to a different context may then be interspersed without affecting any other graphs' context settings. A graphics context is created as follows:
var g = new CvsGraphCtx('canvasID');
The returned object g, has the CvsGraphCtx drawing methods such as setWorldCoords, line, setPenColor, label and so on.
JavaScript graphics drawing code using the CvsGraphCtx will look something like this:
function drawHullo(cvsID) // the canvas ID is passed in as a string
{
var g = new CvsGraphCtx(cvsID); // create a graphics context
g.clearCanvas(); // clear all previous drawing and text
g.setViewport(15, 10, 50, 50); // define square viewport width=50% of canvas width
g.fillViewport("#eeeeb0"); // fill viewport with pale yellow
g.setWorldCoords(0, 1, 0, 50); // scale x axis 0 to 1, and y axis 0 to 50
g.setPenColor("#ff0000"); // use red pen
g.label("Hullo World", 0.5, 25, 5, 20, 15); // x=0.5, y=25, lorg=5, rotate 0°, 15pt font
}
If multiple graphs are to be drawn on the canvas, simply make a new CvsGraphCtx instance for each graph. Typically multiple graphs will each occupy a limited area within the canvas. The setViewport method is used to define a rectangle within the canvas for the graph. The viewport area can be readily filled if a coloured background is required.
The CvsGraphCtx Reference Manual describes all the properties and methods of the CvsGraphCtx.
CvsGraphCtx Examples
Multiple Graphs
Multiple graphs may be drawn on the same canvas. Fig 1 shows several graphs demonstrating some of CvsGraphCtx's capabilities.
Figure 1. Examples of Bar Chart, Point and Line graph and various shapes all drawn on the one canvas.
setRotation() Example
As an example of rotating the coordinate system using the CvsGraphCtx, a set of X and Y axes is drawn in black in Fig 2. The axes are labeled to demonstrate the world coordinates, 0 to 20000 along the X axis and -400 to +400 up the Y axis. A green rectangle has been drawn with its lower left corner at x=2000, y=100. The coordinate system has then been rotated 30° by adding the following line:
setRotation(0, 0, 30);
All drawing after this call is drawn into the rotated coordinate system. To demonstrate the axes have been redraw this time in blue. The rectangle has been redrawn, in yellow, with the same x, y values and now it too has been rotated in accordance with the new coordinate system.
Figure 2. World Coordinates before (black) and after (blue) rotation about world coordinate 0,0.
Image Rotation
A very useful feature of the CvsGraphCtx is its handling of images. There are too commands versions of the image command, drawImage() which loads an image file into memory and then calls updateImage(), which checks that the image object passed has been loaded it then scales, rotates and renders the image onto the canvas. The image width is measured in the units of the X axis, the aspect ratio of the image is always maintained so no height image needs to be passed. The image is placed at the world coordinates passed in. The lorg (locate origin) parameter is also used t determine how the image is placed. Lorg is very useful, it takes values 1 to 9 indicating which of 9 points on the image will be placed at the nominated coordinates. The lorg point will also act a the center of rotation if an optional rotation angle has been passed. The 9 points start with 1 at top left, 2 top center, 3 top right, 4 left center, 5 center of the image and so on, through to 9 being the bottom right. A diagram is shown in CvsGraphCtx Reference Manual.
As a demonstration, let's load an image into figure 2 at point x=10000, y=0 and use lorg 6, i.e. the right middle of the image will be at 10000, 0. The image should be scaled to have width 7000 (X axis units). The command to do this is:
rotGC.drawImg("Images/JaneAvril2.jpg", 10000, 0, 7000, 6);
The Click here to draw the image. If a rotation parameter, say 50 degrees, is passed then the image will be rotated CCW 50degrees with the rotation center at 10000, 0 i.e the right center of the image. Click here to see the effect. If the world coordinates have already been rotated then the image will be placed at the new rotated position and any image rotation will be relative to the new x axis. Click here to see the world coordinates rotated 30 degrees and the image rotated 50 degrees as before.
function drawImage3()
{
var xmin = 0, xmax = 20000;
var ymin = -400, ymax = 400;
rotGC.clearCanvas();
rotGC.setViewport(20, 5, 70, 50);
rotGC.setWorldCoords(xmin, xmax, ymin, ymax);
rotGC.setRotation(0, 0, 25);
rotGC.setPenColor('blue');
rotGC.drawAxes(0, 0, xmin, xmax, ymin, ymax, 2000, 100, 10000, 200);
rotGC.label("X Axis", 20000, 40, 9, 0, 14);
rotGC.label("Y Axis", -3000, -300, 8, 90, 14);
rotGC.rect(12000, 100, 5000, 200, "#aaffaa");
rotGC.drawImg("Images/JaneAvril2.jpg", 10000, 0, 7000, 6, 50);
rotGC.clearRotation();
}
Line Graph
As a simple line plot of two spherical Bessel function.
Figure 3. Line graph example using CvsGraphCtx.
function drawLine(cvsID)
{
var g = new CvsGraphCtx(cvsID);
with (g)
{
setViewport(); // full canvas
fillViewport("#f0f0d0");
setViewport(16, 6, 80, 77); // data area
setWorldCoords(0, 15, -0.5, 1.2);
setPenColor("#000000"); // black pen
drawAxes(0, 0, 0, 15, -0.5, 1.2, 1, 0.1, 5, 0.5);
label("x", 14.5, -0.1, 2, 0, 12);
label("j0(x)", 10.5, 1.2, 6, 0, 10);
label("j1(x)", 10.5, 1, 6, 0, 10);
setPenColor("#ff0000");
move(11, 1.2);
line(12, 1.2);
// plot j0(x)
move(0, 1);
for(var i=0.2; i<=15; i+=0.2)
line(i, Math.sin(i)/i);
setPenColor("#00ff00");
move(11, 1);
line(12, 1);
// plot j1(x)
move(0, 0);
for(i=0.2; i<=15; i+=0.2)
line(i, Math.sin(i)/(i*i)-Math.cos(i)/i);
}
}
Listing 1. Source code for Fig 3.
The drawAxes function simplifies the code considerably. This routine and some other useful graph plotting functions are part of a utilities package cvsPlotUtils-01.js. These utilities are built from the cvsGraphLib methods.
Box Axes Example
The cvsGraphLib can form the basis of more specialised graphics utilities. The cvsPlotUtils-01.js package adds commands tailored to drawing graphs of mathematical functions. It has commands like drawAxes(), as used in Fig 3, and drawBoxAxes() designed with the display of signal processing data in mind. An example of drawBoxAxes is shown in Fig 4.
Figure 4. Example of drawBoxAxes, two instances are drawn on the canvas, code for the upper display is shown.
function drawUpper(cvsID)
{
var data = [];
var g = new CvsGraphCtx(cvsID);
with (g)
{
var h = 50/aRatio;
var vOfs = h;
// Upper display
setViewport(0, vOfs, 100, h);
fillViewport("#303f30"); // very dark
setWorldCoords(0, 100, 0, h);
setPenColor("#a0a0a0"); // grey
setViewport(12, vOfs+6, 85, h-12); // define data area
setWorldCoords(0, 1200, -10, 10);
setPenColor("#c0c0c0");
drawBoxAxes(0, 1200, -10, 10, 200, 5, "Hz", "dB", "REAL");
setPenColor("#ffffff");
data[0] = 0;
data[1] = 0;
for (var i=1; i<=200; i++)
{
data[2*i] = i*6;
data[2*i+1] = 5*Math.sin(i/6);
}
polyLine(data);
}
}
