A Programmer's Guide to Canvas
Written by Ian Elliot   
Article Index
A Programmer's Guide to Canvas
Stacks of states

The HTML5 canvas object provides bitmap graphics to JavaScript, For a programmer's viewpoint of how it all works read on.

 

As long as you are working with a sufficiently up-to-date browser you have two options, at least, when creating graphics in JavaScript a vector drawing option - SVG - and a bitmap drawing option - Canvas.

Although SVG has its advantages many applications and many programmers are much happier working with bitmaps and this means that Canvas is your general purpose graphics element. 

You can use Canvas to create graphics applications, animation and a completely custom UI if that's what you are intereseted in. It also supports 3D graphics by way of WebGL but this is a topic in its own right and in this article we look at 2D Canvas use. 

There are lots of introductions to Canvas for beginning JavaScript programmers so let's take a slightly higher level view of the Canvas object - i.e. Canvas for programmers.

jemsicon

A 2D drawing context

The Canvas object is essentially a bitmap drawing surface. (If you want vector drawing then you need to look at SVG.)

As such the Canvas object provides a drawing context which specifies how the bitmap will be drawn. At the moment there are two types of drawing context, a 2D one and a 3D one. The 3D drawing context is more complicated and perhaps best used via a framework - see Getting started with WebGL - and so we will concentrate on the 2D context.

Creating a drawing context is a two step process.

First you have to create a canvas object and use its getContext("type") to retrieve a CanvasRenderingContext object of the specified type.

Once you have the drawing context you can use it methods and properties to draw on the surface.

The 2D drawing surface has its origin (0,0) at the top left hand corner.  The x axis increases to the right and y values increase going down the page.

The size of the drawing surface is specified as the height and width parameters in pixels.

All drawing commands use pixel co-ordinates but notice that fractional co-ordinates can be used and these shade pixels according to their proximity ot the location - i.e. anti aliasing techniques are used.

There is a subtle point to take note of in that the canvas object also has a Style ,height and width. The style height and width, if specified set the size that the canvas will be displayed at.

The height and width properties specify the number of pixels in the rendering surface and if you specify a Style size the pixels are scaled to fit. This is exactly the same as when you use an <img> tag - the bitmap has a physical size, so many pixels by so many and the heigh and width you specify allocates the space used to display the bitmap.

In short think of the width and height as specifying the size of the bitmap in pixels and the Style width and height as the space that it will be displayed in - with scaling applied if necessary. 

Any drawing operation that specifies pixels outside of the canvas area are simply clipped to fit.

Creating a canvas

So to create a canvas ready for use the usual method is to embed a <canvas> tag where you want it to appear:

<canvas id="Canvas"
    width="300" height="300"
    style="height:600px;width:600px;">
</canvas>

This creates a 300x300 pixel canvas and allocates it a 600x600 display area - each pixel in the bitmap will be scaled to 4 pixels in the page. Of course in most cases we leave the style display size unspecified and then the display area is set equal to the pixel size.

The usual method of getting the drawing context is to use the DOM to retrieve the canvas object and then call the getContext method:

var c = document.getElementById("Canvas");
var ctx = c.getContext("2d");

Once you have the drawing context you can get on with using it via its drawing methods and attributes.

For example to draw a rectangle:

ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(10, 10, 55, 50);

Dynamic Canvas Creation

You can work with the canvas object completely in code if you want to. 

First create the canvas object and set its size:

var c = document.createElement("canvas");
c.width = "500";
c.height = "500";

You can now draw on the bitmap but it wont actually be displayed until you add the canvas object to the DOM, for example:

var ctx = c.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(10, 10, 100, 50);
document.body.appendChild(c);

Notice that this approach allows you to work with a canvas behind the scenes and only show it when you are ready, if ever.

This dynamic approach is so useful that it is worth defining a function to create a canvas:

function createCanvas(h,w){
 var c = document.createElement("canvas");
 c.width = w;
 c.height = h;
 return c;
}

WIth this function our program now reads:

var c=createCanvas(100,100);
var ctx = c.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(10, 10, 100, 50);
document.body.appendChild(c);

If you do want to display the canvas as soon as it is created you can use something like:

var c=document.body.appendChild(createCanvas(100,50));

and if you never want to refer to the canvas object again you could even write:

var ctx =document.body.appendChild(
            createCanvas(100,50)).getContext("2d");

 

graphicsicon

Paths

In general the drawing methods work by creating a path which you can then fill or stroke (draw as an outline). 

A path is an abstract geometric thing and to make it visible you have to assign a stroke to it color and thickness. If you also assign a fill then the interior of the path is filled with the specified color. 

You start a path using the beginPath() method or simply moveTo(x,y). There are various line drawing commands such as lineTo(x,y) and once you have a path completed you can render it using the stroke() and/or fill().

The path is drawn using the current set of drawing attributes - lineWidth, fillStyle and so on.

There are also the fillRect and strokeRec methods which can be used as a shortcut to a path and drawing it.

Stack of states

So far so good.

We can now create a drawing context which is essentially a bitmap with an associated drawing state - the canvas state. This is a set of properties that determines how graphics primitives will be drawn.

The state consists of

 

  • the current transformation matrix
  • the current clipping region
  • all of the drawing attributes such as fillStyle, lineWidth and so on.

 

In short everything that determines what the result of a drawing operation actually produces. Notice that any drawing operation that is in progress, such as the current path or current bitmap, are not part of the state.

Why are we concerned with defining the context state?

The answer is that there is a save method which saves the current state to an internal stack of states and a restore method that sets the state to the current top of stack. 

So for example you can set a fill color and save it on the stack of states:

ctx.fillStyle = "rgb(200,0,0)";
ctx.save();
ctx.fillStyle = "rgb(0,200,0)";
ctx.save();
ctx.fillStyle = "rgb(0,0,200)";
ctx.fillRect (10, 10, 55, 50);

At this point the current fill colour is blue with green and red on the stack. Hence we have just drawn a blue rectangle.

If we now restore from the top of the stack  and draw a rectangle it will be green:

ctx.restore();
ctx.fillRect (20, 20, 55, 50);

Repeat this another time and we draw a red rectangle

ctx.restore();
ctx.fillRect (30, 30, 55, 50);

Notice that in this case we are only changing the fill color but in practice the entire drawing state is saved and restored.

squares

You can use the state stack to change the drawing state to draw a sub object and then restore the state to continue with drawing the main object.

 

Banner

<ASIN:0137054890>
<ASIN:0596517742>



Last Updated ( Tuesday, 23 September 2014 )
 
 

   
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.