An introduction to the Canvas 2D API

by .

If the <video> element is the poster boy of HTML5, then <canvas> is definitely Danny Zuko. The <canvas> element is (still) part of the HTML5 specification, but the 2D drawing API has been moved into a separate document (in case you go looking and can’t find it).

<canvas> has a wealth of features, like:

  • drawing shapes,
  • filling colours,
  • creating gradients and patterns,
  • rendering text,
  • copying images, video frames, and other canvases,
  • manipulating pixels, and
  • exporting the contents of a <canvas> to a static file.

In fact, the canvas API is so interesting, I wouldn’t be surprised to see entire books dedicated to it (and no, I don’t plan to write that book!).

It’s important when working with <canvas> to treat it like a real painting canvas. Say you lay down a strip of red paint on a real canvas. If you paint over it in blue, you can’t get back to your original red paint. It’s the same with the canvas element. There’s no concept of layers. The <canvas> element is a bitmap drawing API, and once you’ve committed to a set of pixels, you’re stuck with them.

Four of the Big Five browsers support canvas. We’re naturally missing IE8, but there’s hope: IE9 does support canvas. In fact, it supports hardware accelerated drawing to the canvas — other browsers currently don’t, making IE9 preview 3 the fastest (canvas) kid on the block!

Always consider the options

Before we dive in to the canvas API, I want to remind you to make sure you’re using the right technology for the job.

SVG is the alternative drawing API. It’s vector-based and does support layers. SVG also exists in the DOM, making it easy to attach event handlers for interactivity, and it’s easier to deal with collision detection (in games, for example). It also supports animation either through SMIL or JavaScript. There’s an excellent JavaScript library called Raphaël that uses SVG to render images and animations.

The <canvas> element is good for pixel manipulation and highly active animations. Brad Neuberg does a really good job of explaining the differences in his Google IO talk from back in 2009.

With all that in mind, let’s crack on with the canvas API.

Hello Canvas

The <canvas> element by itself is an invisible block of space, by default 300×150 pixels (in all browsers):

<canvas id="c"></canvas>

So now we’ve got a blank canvas in front of us. To draw, we need the drawing context, which we can get using JavaScript. Once we have the context, we can draw abominations to our hearts’ content:

<script>
// declare the two variables at once using a comma
var canvas = document.getElementById("c"),
    context = canvas.getContext("2d");

// now you're ready to draw
</script>

Code snippet

The context is our direct access to draw and paint on the canvas. Without it, we can’t paint a thing.

Painting Shapes

The 2D drawing API is fairly large (not too huge, but bigger than most other HTML-esque APIs), so I’m just going to show you how to draw something simple: a solid blue rectangle and a pink semi-circle.

Using the context object from earlier, we’re going to call fillRect(), passing the method the coordinates of the top left corner (x, y) and the width and height of the rectangle we want to paint:

<script>
var canvas = document.getElementById("c"),
    context = canvas.getContext("2d");

// x = 10, y = 20, width = 200, height = 100
context.fillRect(10, 20, 200, 100);
</script>

Code snippet

Simple filled rectangle
Simple filled rectangle created with canvas

If you don’t specify a colour, the default fill and stroke colours will be black. So let’s change that to blue by setting the fillStyle() before we call fillRect(). We’re choosing our colour before drawing because this <canvas> is just like a real canvas — if you’re going to paint, you need to dip your brush in to the paint pot first:

var canvas = document.getElementById("c"),
    context = canvas.getContext("2d");

context.fillStyle = 'blue';
context.fillRect(10, 20, 200, 100);

Code snippet

Blue filled rectangle created with canvas

Being the eagle-eyed HTML5 ninja that you are, you noticed that I’ve used the string blue as the fill colour. You can use any CSS colour properties in the canvas API. That means blue, #0000ff, #00f, rgb(0, 0, 255), and even rgba(0, 0, 255, 0.5) are all valid colours.

How about we turn this thing up to eleven? Let’s add a pink semi-circle. Oh yeah! Let’s do this!

var canvas = document.getElementById("c"),
    context = canvas.getContext("2d");

context.fillStyle = 'blue';
context.fillRect(10, 20, 200, 100);

// setup the line style
context.strokeStyle = '#fa00ff';
context.lineWidth = 5;
context.lineCap = 'round';

// draw the arc path
// (I'll walk you through these values momentarily - bear with me!)
context.arc(50, 50, 20, 0, Math.PI, false);

// colour the path
context.stroke();

Code snippet

Blue filled rectangle with a semi-circle created with canvas

There are three things that we’ve added to our JavaScript:

  1. Configuring the line style
  2. Drawing the semi-circle path
  3. Stroking the path (i.e., painting the line)

When drawing paths, until you fill or stroke the path, nothing appears on the canvas. In this case, our path is an arc of a 180 degrees. The arc() method takes the following arguments: x coordinate, y coordinate, radius, start angle, end angle, and whether the arc should be drawn anti-clockwise. All of these arguments are required. (Technically, if you’re drawing a circle, it doesn’t matter whether you’re going clockwise or anti-clockwise, but you still need the argument.)

The tricky parts are the start and end angle. They’re both in radians. Remember those? I didn’t, so I’ll forgive you if you don’t! Here’s how to convert from degrees to radians:

var radians = degrees * Math.PI / 180;

It’s common to pass 360 degrees to the drawing methods, which is simply Math.PI * 2. Similarly, 180 degrees is Math.PI, which we used to create our semi-circle.

Once you have your path, you need to stroke (or fill) it. This applies the line style and colours to the path and completes our drawing. Do please remember that with this drawing: a) you can’t recover those lost blue pixels under the pink semi-circle, and b) this example would be much simpler in SVG!

So remember to choose the <canvas> element based on its strengths as I outlined at the top of this article.

Exporting & Saving

One thing that SVG can’t do is save the resulting image as a bitmap. It’s easy for <canvas> because the element is already a bitmap in the first place! The canvas can export its image to a data URL (e.g., data:image/png;base64,iVBORw0KGg...). This data may then be rendered in the browser, which could then be saved or dragged to the desktop, used in a new canvas, and so on.

The browser must support PNG images, and it may have varying support for GIF and JPG. For our example, we’ll stick with PNG since it supports alpha transparency, and where we haven’t drawn on the canvas, it’ll be transparent.

To get the data URL, we 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 taking the example we’ve put together already, we’ll make the browser redirect to a PNG version of the image when a user clicks on the <canvas> element (a contrived example, I know!):

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

Code snippet

If you go to the live canvas example and click on the <canvas> element, it will load a PNG version of the canvas. Now you can save that to your desktop, email it to your friends, or even tweet it to your followers!

That’s just the start

This is just a small preview of what the canvas 2D API can do. There’s a whole lot more:

  • Gradients, fills, and patterns
  • Paths
  • Text
  • Pixel manipulation
  • Animations (though old school, flip book style)

And don’t worry, the HTML5 Doctors will publish more articles explaining the canvas API in the future. We’ll even have special guest Tab Atkins explaining how he got a video to render entirely in ASCII!

In the meantime, here are a few useful resources to keep you going.

Further reading

24 Responses on the article “An introduction to the Canvas 2D API”

Leandro says

Cool!

I hope more advanced articles!!

Leandro says

fiiirrrrssssssssstt comment! :D

Andi Smith says

If anyone makes anything cool with canvas, feel free to submit it to canvasdemos.com!

Alexis Deveria says

Excellent article as usual, Remy!

Funny story: I first experimented with Canvas using Mozilla’s original tutorial, and I actually thought that was SVG! Was surprised at the time to find out there were actually two ways for browsers to draw pretty shapes.

And yeah, it sucks that there’s no easy way to save an SVG as a bitmap…for anyone who needs to do so anyway, I’d recommend the Canvg project.

Jason says

Is it weird that I literally had Joe Swanson’s voice in my head as I read “Oh yeah! Let’s do this!” before I clicked on the link to the Family Guy clip?

Nathan Williams says

Thanks a lot for the details. We had some great fun trying it out. Bit amateurish to display. Will take some time to get the hang of it. Look forward to more about HTML5 canvas and its possible applications. Great post, Remy keep up the good work.

Richard Clark says

Thanks Philippe, we’ve updated the post.

Ciarán says

I look forward to seeing how IE9 preforms with canvas. And other browsers in general, as at the moment canvas is still quite slow. Good article

J.F. Herrera says

Great tutorial. Big things are ahead for HTML programmers.

Ben says

You didn’t mention excanvas that allow interpretation of canvas tag with IE6, 7 and 8 (using VML).

About saving image as a bitmap, I feel it useful to use SVG : I can build the svg file on the server-side for other purposes (generating PDF with charts for example)

Ben says

Just forgot to tell how I convert svg to bitmap server-side : I use Batik

happy says

What a wonderful post!I like what you wrote, I believe you also like what I would recommend.someday,i find my favoraite shop,in this shop, you can find huge selection of armani glasses
Best of luck for you

bhupi says

Hey… Cool..

but what, if the background of canvas is some external image with any format and drawn on the canvas and some graphic drawn on foreground. How to fetch the complete set of objects on the canvas?

As far as I know the “toDataURL” method returns objects which are created graphic kind of something but not Image?

bhupi says

Hey… Cool..

but what, if the background of canvas is some external image with any format and drawn on the canvas and some graphic drawn on foreground. How to fetch the complete set of objects on the canvas?

As far as I know the “toDataURL” method returns objects which are created graphic kind of something but not Image ?

Remy Sharp says

@bhupi – there’s no such thing as an “object” WRT the canvas. If it’s painted on the canvas, then toDataURL will give you an image representation of it. Anything behind the canvas is just that: *behind* the canvas, and therefore not part of it.

Moniker says

It would have been helpful if you had included this code between the javascript code for canvas:

window.onload = function() {

}

I do not know any javascript and wasted quite some time trying to figure out what I was doing wrong.

Thanks

Remy Sharp says

@monkier – actually if you actually looked at the example code samples provided in this article, you would have seen the JavaScript was below the canvas element so you don’t need the window.onload.

In fact, you shouldn’t use window.onload at all – maybe it’s time to learn JavaScript since you even admit you don’t know it?

Monkier says

@Remy

I looked at the example code. By omitting the other elements in the example code, I had to make assumptions and that is what I did.

Anyway, my fault for not knowing any javascript.

Jamna says

Hi ,
Great article !!!..Remy
thanks for it.

I am learning HTML 5 in these days… so little confuse on some places …

what is “drawing context” exactly ?

what is the role of getcontext() method?

why we always pass the string “2d” to the getContext() method, why not”3d”?

Is there a 3-D canvas?

if anybody can give me answers of these question…it will help me to understand this element.

thanks

anamitra says

When we’re drawing a line or a pie chart using canvas,how can we show a tooltip for every individual section of a pie or every line of a line chart?Please suggest.I’m currently using filament group for drawing charts,which uses canvas implicitly.

Anirudh says

This is good and is little summary about the canvas. But want advanced tutorial like two different people working on same canvas and can see the changes made by other on that canvas.

Rogama says

Hi!!
Excelent tutorial, but… How to use the method Bitmap()??

thank regard

Join the discussion.

Some HTML is ok

You can use these tags:
<a href="" title="">
<abbr title="">
<b>
<blockquote cite="">
<cite>
<del datetime="">
<em>
<i>
<q cite="">
<strong>

You can also use <code>, and remember to use &lt; and &gt; for brackets.