An Introduction to the HTML5 Canvas API

Supported Browsers: Opera 10.5+, Firefox 3.5+, Safari 3.0+, IE 9.0+, Chrome 9.0+

By Alexander Jones,

Introduction

The HTML5 specification defines canvas as “The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, or other visual images on the fly.

In its most basic definition; it’s a square on a web page where, by using javascript anything you want can be drawn, as an element <canvas> will be show nothing on the page because it has no content.

Canvas has a lot to it and boasts a number of features including the ability to draw shapes, create patterns and gradients, colour filling and pixel manipulation and also allows exporting to static files.

1. Fall Back

Four of the main five browsers support canvas, with IE8 currently not doing so. IE9 however, does support canvas and it supports the extra feature; hardware accelerated drawing to the canvas which is something that other browsers currently don’t have, making IE9 the browser to use when developing and using <canvas>.

Because the <canvas> element is relatively new and is not supported in some browsers like Internet Explorer versions below IE9, it’s important to have a fall back option available for when the browser doesn’t support the element. This can be done by providing alternative content inside the <canvas> element, the browsers which don’t support the <canvas> element will just ignore the container and then render the fall back content inside it

Doing this will of course mean that browsers which do support the <canvas> element, will just ignore the alternative content and just render the canvas content as it should be. An example of this would be to supply an alternative image for the dynamically rendered <canvas> content shown below:

<canvas id="tiger" width="150" height="150">
<img src="images/tiger.png" width="150" height="150" alt=""/>
</canvas>

Scripts can also check also check for support when they execute, this can be performed by testing for the getContext method, and the following shows how:

var canvas = document.getElementById('tutorial');
    if (canvas.getContext){
    var ctx = canvas.getContext('2d');
    // drawing code here
    } else {
    // canvas-unsupported code here
}

Required </canvas> tag

In the Apple Safari implementation, <canvas> is an element implemented in much the same way <img> is; it does not have an end tag. However, for <canvas> to have widespread use on the web, some facility for fall back content must be provided. Therefore, Mozilla's implementation requires an end tag (</canvas>).

If fall back content is not needed, a simple <canvas id="foo" ...> </canvas> will be fully compatible with both Safari and Mozilla -- Safari will simply ignore the end tag.

If fall back content is desired, some CSS tricks must be employed to mask the fall back content from Safari (which should render just the canvas), and also to mask the CSS tricks themselves from IE (which should render the fall back content).

2. Why use Canvas and not SVG? Consider the Options

Until recently you really couldn’t draw on the web and the web itself didn’t really provide primitives to actually draw things on the screen and the graphics weren’t very interactive, they didn’t work well with javascript, the option was to use the plugins to help you to deploy the fancy things that were needed on the web including Microsoft’s VMI, flash and Silverlight.

Canvas and SVG embed themselves into the web and are a part of the html mark-up within the sites that we build.

SVG

SVG (scalable vector graphics) like canvas, exists in the DOM of a page, making it easy to attach event handlers for interactively and it can easily deal with collision detection (e.g. in games) and supports animations through javaScript and through HTML5 are new tags which can be used for drawing, for example to draw a rectangle you use a rectangle tag:

<svg width="200" height="200">
<rect X="0" y="0" Width="100" height="100"
    Fill="blue" stroke="orange"
    Stoke-width="5px"
    Rx="8" ry="8" 
    Id="myRect" class="chart" /> 
</svg>

SVG is a web standard that pre dates HTML5, but HTML5 tells us 'heres how you drop svg into a normal html page' with html like tags that do drawing right inside html. They integrate well, they are not just static graphics, we can manipulate, animate and interact with them. So let’s play with our rectangle in javascript:

var rect = document.getElementById('myRect');//grabs the element
    rect.style.fill = 'yellow'; //changes its properties
    rect.onclick = function() { alert('hello'); }; //add interaction 

Click here to view the example in jsbin.

SVG is higher level and should be used when you want to import and export graphical assets, you can export to illustrator. SVG is a retains mode API, (both are needed for different functions), whenever you want to create easy user interfaces because SVG is a retains mode API it means there is a tree of everything that’s been added to the screen so it’s easy to do detections and adding events because you can attach events to something in the tree.

It’s good for interaction and medium animations, but canvas is lower level and is great when you don’t need the tree and want to have keyboard interaction, its JS centric and has higher animation involving more pixel orientation. It’s important to choose both in the right situations.

Canvas

In HTML5, the Canvas API, is like a scriptable image tag, as opposed to SVG which is a tree format and is delivered in the mark-up, canvas is like an image tag that javascript can customise;
The basic <canvas> mark-up (with an id) looks like the following:

<canvas id="a"></canvas>

This will have no content and will ‘appear’ as an invisible block of space, to draw you need to have some drawing context which can be declared using javaScript, and once this is obtained, the drawing can take place.

<script>
    // declare the two variables at once using a comma
    var canvas = document.getElementById("a"),
        context = canvas.getContext("2d");
    // now you're ready to draw
</script>

The 2d drawing API is large and the following code shows how easy it is to create something simple, two rectangles, one red, one blue with 50% opacity.

<html>
<head>
<script type="application/javascript">
    var canvas = document.getElementById("canvas");
    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

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

        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
        ctx.fillRect(30, 30, 55, 50);
    }
</script>
</head>
<body>
<canvas id="canvas" width="150" height="150"></canvas>
</body>
</html>

It will look like this:

Click here to view the example in jsbin.

Unlike SVG, canvas only supports one primitive shape, rectangles. To give an idea of the scale of the library, the following are the methods and properties for drawing just rectangles.

  • The fillStyle property can be a CSS color, pattern or gradient, if a colour isn’t specified, the default is black. The drawing context remembers its properties as long as the page is open.
  • The stokeStyle property is like fillStyle, it can be any colour, gradient or pattern and just allows you to put a stroke around an object.
  • stokeRect (x, y, width, height) draws a new rectangle with the current stoke style. stokeRect just draws the edges.
  • fillRect (x, y, width, height) draws a filled rectangle.
  • clearRect (x, y , width, height) clears the pixels in the chosen rectangle.

Each <canvas> has a drawing element, which is where the 'creative' side of thing’s happens, once a <canvas> element has been defined in the DOM by using document.getElementById() the getContext() method is called, and the string ‘2d’ is passed through:

var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
b_context.fillRect(50, 25, 150, 100);

Calling the fillRect() method draws the rectangle and fills it with the current fill style, which colour is black as default. The rectangle is bounded by its upper-left corner (50, 25), its width (150), and its height (100).

Before it’s possible to understand the drawing possibilities and get going, it’s important to get to grips with the coordinate space.

Coordinate Space

If the canvas element is specified at 200 pixels wide and 200 pixels high, by default 1 unit in the grid corresponds to 1 pixel on the canvas. The origin of this grid is positioned in the top left corner (coordinate (0,0)). All elements are placed relative to this origin. So the position of the top left corner of the blue square becomes x pixels from the left and y pixels from the top (coordinate (x,y)).

Canvas Coordinate Image
Canvas Coordinates Image

3. Drawing Paths

As discussed earlier, canvas only supports one primitive shape, a rectangle. Anything else must be drawn by creating and combining paths, with rectangles, there is a set of functions which draw the rectangle immediately onto the canvas, but to make shapes using paths, a couple of extra steps are required.

beginPath()-The first step to create a path is calling the beginPath method. Internally, paths are stored as a list of sub-paths (lines, arcs, etc) which together form a shape. Every time this method is called, the list is reset and we can start drawing new shapes.

closePath()- This method tries to close the shape by drawing a straight line from the current point to the start. If the shape has already been closed or there's only one point in the list, this function does nothing.

stroke(),fill()- The final step will be calling the stroke and/or fill methods. Calling one of these will actually draw the shape to the canvas. Stroke is used to draw an outlined shape, while fill is used to paint a solid shape. For example, the code needed for drawing a triangle would look like this:

ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(100,25);
ctx.fill();

moveTo

One function, which is like lifting a pencil from one spot on a piece of paper and placing it on another spot, is moveTo. It has two argumeents, x and y which are the coordinates of the new starting point. This would typically be used when the canvas is initialised or the beginPath method is called, or you can use it to draw unconnected paths.

moveTo(x, y)

The following is an example of drawing a smiley face with the moveTo method, if you remove the moveTo method you will be able to seee the connecting lines, the help to understand the arc function look below the example:

var canvas = document.getElementById("canvas2");
var ctx = canvas.getContext("2d");

    ctx.beginPath();
    ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
    ctx.moveTo(110,75);
    ctx.arc(75,75,35,0,Math.PI,false);   // Mouth (clockwise)
    ctx.moveTo(65,65);
    ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
    ctx.moveTo(95,65);
    ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
    ctx.stroke();

It will look like this:

Click here to view the example in jsbin.

lineTo

For drawing straight lines, the lineTo method is used:

lineTo (x, y)

Taking two arguments, x and y, which are the coordinates of the line’s end point, the starting point depends on the previous drawn paths, which of course can be changed by the moveTo method.

Arc

For drawing arcs or circles the arc method is used:

arc(x, y, radius, startAngle, endAngle, anticlockwise)

This method takes five parameters: x and y are the coordinates of the circle's center. Radius is self-explanatory. The startAngle and endAngle parameters define the start and end points of the arc in radians. The starting and closing angle are measured from the x axis. The anticlockwise parameter is a Boolean value which when true draws the arc anticlockwise, otherwise in a clockwise direction.

Angles in the arc function are measured in radians, not degrees. To convert degrees to radians you can use the following JavaScript expression: var radians = (Math.PI/180)*degrees.

4. Exporting and Saving

Another thing that separates canvas from SVG is the ability to save the created image as a bitmap. This comes naturally for a <canvas> element because the element is a bitmap in the first place. The canvas can export its image to a data URL (e.g. data: image/png.image…). Which may then be rendered in the browser, and then could be saved. The browser must support PNG images and may have different support for JPG and GIF. PNG is advantageous because it supports alpha transparency, so on the canvas where nothing has been drawn, it’ll be transparent.

To get the data URL, simply call canvas.toDataURL('image/png'). Note that we’re calling toDataURL() on the <canvas> element, not on the 2D context. This is because we’re getting all the pixels in the canvas, not just the pixels in a particular context. So as an example, it’ll make the browser redirect to a PNG version of the image when a user clicks on the <canvas> element:

canvas.onclick = function () {
    window.location = canvas.toDataURL('image/png');
};

5. Conclusion

Personally I think that canvas is one of the most interesting features of HTML5, offering a huge amount of scope for development and functionality. It's ready to be used within most modern browsers and gives a huge 2D context API with a wealth of features allowing the creation of games, interface enhancements and all sorts of a other things (even fun stuff!).

The Next Step

This tutorial focuses on some of the main areas of the Canvas API and introduces the elements needed to get going and have a play with it. There’s an awful lot more including:

  • More paths methods and functions.
  • Colour manipulation and transparency.
  • Gradients, fills and patterns.
  • Text
  • Pixel Manipulation
  • Animations

Be sure to head over to the demos sections to have a look at some examples, and also there’s plenty of great Canvas resources to get more informed about the API: