CANVAS LAYERS
The Benefits of Layers
The canvas element is designed to allow script driven graphics on web pages without using proprietary plugins like Flash®.The canvas is a 2D drawing surface with a quite powerful set of drawing methods, but the individual items drawn on the canvas are all flattened to create a single image. A lot of code is often required to generate a picture even if a graphics context such as CvsGraphCtx handles all the scaling of coordinates and so on. When a canvas is used for animation, the flat image requires a complete redraw for each animation frame, even if only one drawing item is changed.
The traditional animation technique is to use a stack of transparent layers overlaying a background image, with the items to be animated each being drawn on a separate layer. Only the layers that change on each frame are redrawn and the other layers are left unchanged. The graphics engine can sort out the exposed areas to be redrawn from underlying layers without user code being required.
The CanvasStack
A stack of canvas layers suitable for animation on a web page can be created and managed using a JavaScript CanvasStack. This comprises a background canvas and an (initially empty) array of transparent canvas layers along with methods for creating a new canvas layer and deleting layers.
Each new layer is a transparent canvas the same size as the background canvas and positioned directly over it. It may be drawn onto with the same methods as the background or any canvas element. Those areas left blank are transparent and the underlying canvas content will be visible. The layer contents may be erased and the underlying drawing so exposed will show through with no user code required for redrawing.
Creating the CanvasStack requires a HTML DIV element to act as the stack holder. This is added to the page and positioned in the document as normal, its width and height will set the size of the canvas layers in the stack. After the document is loaded (and the holder DIV exists) the CanvasStack constructor is called passing the ID of the holder DIV. The newly created CanvasStack object creates the background canvas and creates an (empty) array for the overlay canvases. Each subsequent calls to the CanvasStack method createLayer will create a new transparent overlay canvas. Typical setup code is as follows:
Firstly download the library canvasStack1v00 and ensure that it will be loaded by including in the document header the following:
<script type="text/javascript" src="canvasStack1v00.js"></script>
To insert a CanvasStack into a web page, place a DIV element within the document with the size and position you wish the canvas to have. Give the DIV a unique ID. The following HTML snippet shows and example using inline style to set the width and height:
<div id="holderId" style="position:relative; width:500px; height:300px"></div>
The style need not be set inline as shown above, but may be set by CSS style sheet.
The canvas stack for this holder DIV is created by the CanvasStack constructor which is passed the ID of the holder DIV. The size and position of the background canvas will be set to exactly overlay the holder DIV. An optional background color may be passed to the constructor, the color is specified as a string in any of the HTML standard forms, "rgb(r, g, b)" or "#rrggbb" or any of the named standard colors such as "wheat" or "blue" etc. If the color if omitted the background canvas will be transparent and the contents of the holder DIV will show through. If the background color is specified clearing the background canvas will return to the background color not to transparency. A example of creating a CanvasStack is as follows:
var cvsStk = new CanvasStack('holderId', "white");
The returned CanvasStack object has the following methods:
getBackgroundCanvasId,createLayer,
deleteLayer,
deleteAllLayers,
To draw in the background canvas or in the layers, requires a graphics context. To create a cvsGraphLib graphics context use the CvsGraphCtx constructor as follows:
cvsCtx = new CvsGraphCtx(canvasID);
The CanvasStack method getBackgroundCanvasId() returns the canvas element ID that is passed to CvsGraphCtx constructor.
To use the native canvas context for drawing, create the graphics context with the canvas element getContext method:
ctx = document.getElementById(canvasID).getContext('2d');
Creating a New Layer
To create a CanvasStack layer simply call the createLayer method, the ID of the canvas created will be returned. The new transparent canvas will be placed on top of all the other layers already in the stack. A typical call to create a layer is as follows:
var layer1_ID = cvsStk.createLayer(); // create a new layer, its ID string is returned
Drawing in the Layer
Once the new layer has been created a graphics context must be created to draw into the new canvas. If drawing with the cvsGraphLib the call is the same as for the background canvas:
L1_ctx = new CvsGraphCtx(layer1_ID);
All the CvsGraphCtx commands are available as methods of the L1_ctx.
To create a native canvas context, a reference to the canvas element rather than its ID is used as follows:
var L1_ctx = document.getElementById(layer1_ID).getContext('2D');
CanvasStack Example
The clock from the Mozilla canvas animation tutorial shown in Fig 1. It has been drawn using the CvsGraphCtx, rather than the native canvas methods shown in the tutorial. Two layers were used, the background canvas holds the image of the face and with no hands and the second layer is used to draw the hands. Every second the 'hands' layer is cleared and the hands are redrawn rotated to show the new time.
The code to create the CanvasStack and the graphics context to start drawing is as follows:
In the body of the document the holder DIV was created:
<div id="clockHolder" class="cvsEg"></div>
The style rules for class cvsEg set the width and height.
The call to draw the clock was made by the onload property of the body element:
<body onload="drawClock('clockHolder')">
....
The drawClock function then created the CanvasStack and a graphics context for drawing in the background layer, where the clock face will be drawn. Then creates a layer for drawing the hands, and a graphics context for this layer. Here is th first few lines:
function drawClock(holderID) // pass the holder DIV id
{
clockCS = new CanvasStack(holderID, "wheat"); // use a global just for demo
var bkgID = clockCS.getBackgroundCanvasId();
var g = new CvsGraphCtx(bkgID); // g is the graphics context for the background
var L1_ID = clockCS.createLayer(); // create a new layer for the clock hands
var gL1 = new CvsGraphCtx(L1_ID); // gL1 is the graphics context for 'hands' layer
g.setViewport(25, 5, 50, 50); // start drawing the face in the background canvas
g.fillViewport("white");
...
Here is the clock drawn on a "white" square in the "wheat" colored canvas.
Figure 1. The basic clock with hands drawn on a separate layer.
To demonstrate the independent of the layers in the CanvasStack let's create a new layer, write "Hullo World" across the clock. In the flattened canvas drawing, such as used in the Mozilla tutorial, the 'Hullo World' would be written into the same canvas as the clock face and hands. When the next redraw occurs, one second later, the "hullo World" would be cleared. With a CanvasStack "hullo World" is on a separate layer and the clock hands will keep on moving on their own layer.
Now try this code, click here. It will draw "Hullo World" over the clock in Fig 1. Click here to erase the "Hullo World". The clock hands continue ticking along, independent of the other layers.
The source code for drawing 'Hullo World' is shown below, Note: the CanvasStack on which the clock is drawn is the global clockCS:
function drawHullo()
{
ovlyID = clockCS.createLayer(); // create canvas layer (save ID for later reference)
var oCtx = new CvsGraphCtx(ovlyID); // create an graphics context for overlay
oCtx.setViewport(20, 20, 50, 50); // define square viewport width=50% of canvas width
oCtx.setWorldCoords(0, 10, 0, 10); // scale x axis 0 to 10, and y axis 0 to 10
oCtx.setPenColor("#ffa500"); // use orange pen
oCtx.label("Hullo World", 5, 4, 5, 20, 30); // x=5,y=4 lorg=5, rotate 20°, 30pt font
}
CanvasStack constructor
CanvasStack
Syntax:
new CanvasStack(holderID:String, fillColor:String);
Description:
Creates a new CanvasStack object comprising a background canvas element and an array (initially empty) of transparent canvases. If the optional fillColor String is present and represents a valid HTML color format, the background canvas element will have its 'background-color' property set to fillColor. If fillColor is omitted the background canvas will be transparent and the contents of the 'holder' div will show through.
Parameters:
holderID:String - The ID of the DIV that acts a the parent element to the canvases in the stack. The width and height of this DIV set the size of the canvases in the stack.
fillColor:String - The fill color to be used. The fill color may be expressed in any of the four canvas color formats:
- Hex notation "#rrggbb", where rr sets the red level (00 to ff), gg sets the green and bb sets the blue level.
- RGBA notation "rgba(r, g, b, a)" where r, g and b are decimal numbers in the range 0 to 255 representing the red, green and blue levels respectively and a is the alpha or transparency value 0 (transparent) to 1.0 (opaque).
- RGB notation "rgb(r, g, b)" where r, g and b are decimal numbers in the range 0 to 255 representing the red, green and blue levels respectively.
- Predefined colors names eg. "red", "blue", "maroon", "palegoldenrod", "wheat" etc. There are 140 standard color names in the extended color list.
CanvasStack Methods
getBackgroundCanvasId
Syntax:
cvsStk.getBackgroundCanvasId();
Description:
Returns the ID string of the background canvas element.
The ID is required to create a graphics context to enable drawing in the background canvas.
Parameters:
none.
createLayer
Syntax:
cvsStk.createLayer():String;
Description:
Creates a canvas layer the size of the underling background canvas and positioned to directly overlay it. The canvas is stacked to be above all previously created layers. The canvas is transparent.
Parameters:
none.
Returns:
String - The canvas element ID property. This ID is required to create a graphics context to enable drawing into the canvas layer.
deleteLayer
Syntax:
cvsStk.deleteLayer(layerID:String);
Description:
Deletes the canvas layer with ID=layerID. The layers canvas element is deleted from the document. Any further references to drawing in this layer will fail.
Parameters:
layerID:String - The ID of the canvas to be deleted.
deleteAllLayers
Syntax:
cvsStk.deleteLayer()
Description:
Deletes all the canvas overlay layers from the cvsStk. The background layer is not deleted. Each layer's canvas element is deleted from the document.
Parameters:
none.
