Before beginning this section make sure you keep two principles of JavaScript coding in mind. Always use your console to help in debugging your code (it will work as well with canvas objects as any other JavaScript object), and remember that any script that references the DOM itself must come after the DOM for it to find the elements you are referencing.

What is Canvas?

HTML5 introduced a new html element called "canvas". A "canvas" object essentially a div that can be used by JavaScript for advanced drawing techniques not suitable to basic HTML and CSS code. It would be overkill for a web designer to use a canvas object for anything that can be done with basic web tools so the situations where you should use it are fairly specific.

These are just a few examples of popular uses...

  • Animations dependent on other conditions such as icons that change based on form options.
  • In-browser painting or image manipulation programs (though loading / saving is not typically an operation of a canvas object).
  • Web-based video games that are more complex than simple point and click games (such as card games). Anything that requires constantly moving characters, projectiles, or other sprites that appear in arbitrary places on the screen (such as shmups, action platformers, etc).

It is written just like any other HTML element would be and will only, for most uses, need a single identifier as an attribute. They can be styled with CSS, to an extent, but most of the CSS related to your canvas objects will be positional styling.

Let's look at a simple canvas implementation on the DOM side of things.



<html>
<header>
<style>

#canvas_name {
	position: relative;
    margin-left: 20px;
    margin-top:  40px;
    
    background-color:pink;
    outline:1px solid black;
}

</style>
</header>
<body>

<canvas id="canvas_name"></canvas>

</body>
</html>
<script>

// Canvas editing code will go here.

</script>

That's basically it. Our CSS only defines the position properties, and in this case, a visual touch in the form of an outline. We don't even need to define the size of the canvas object. We can, but it will otherwise automatically take on the size defined by the contents we fill it with, so defining a size in our CSS would be purely for development purposes.

It may also help to define a "background-color" so that you can know where your canvas is actually appearing. If anything goes wrong with your JavaScript code you will at least see this color. But even that is not required.

For the code that will actually appear in the script section of this example we'll walk through the minimal amount of code required to define the properties of a canvas and draw a simple shape to it.



////////////////////////////////////////////////////////////////////////////////
// Canvas objects

// Like any HTML element that you wish to edit with JavaScript you'll need to
// create a reference to the element in the form of a variable.  This is done in
// the same way yoa'd reference any variable - with a "getElementById".

var canvas = document.getElementById("Canvas");

// Now at this time we can define the size of the contents of the canvas.  We
// use two inherent properties of the canvas, "width" and "height", which will
// automatically size the element within our page.

canvas.width  = 700;
canvas.height = 400;

// We need to do this because, depending on the browser, if it is not defined
// then we may not be able to draw outside the default area of a canvas element
// which is typically only 200 to 300 pixels across.

// Here is where things get more involved.  Another inherent quality of a canvas
// object is the "Context".  The context is basically where the actual visual
// information of the canvas is stored on a pixel level.  It is actually the
// CONTEXT, and not the name "canvas" itself that draw commands will be tied to
// in further code.  Thankfully a context does not have to be created, we simply
// create a reference to it as we did the canvas itself.

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

// The abbreviate "ctx" is simply an accepted indsutry standard way of 
// truncating the word "context".  You may use whatever word or phrase you like
// for these variables as long as they appear in the appropriate places.

// The argument "2d" that you see above is a reserved argument.  You'll pretty
// much never have to change this for that vast majority of canvas uses, and 
// will not have to use any other argument for these examples.  You can create
// your context 

// Now let's draw a simply rectangle shape to our canvas.

// What you'll find out when it comes to drawing on canvas objects is that many
// of the default methods that you'll use to draw shapes are already available
// to you and will take fairly straight forward arguments as instructions to
// draw those shapes.  For instance the Rectangle drawing method below takes
// four numbers as arguments to draw a single shape.

// But before that we need to choose a color for our rectangle.

// For many shapes we can define a "fill style".  Assigning a single value to
// this property will define what will be the color of the shape.
ctx.fillStyle = "rgb(64,128,255)";

// "fillStyle" can also take plain english colors and hexadecimal colors.

// The actuall drawing of the rectangle happens when we invoke "fillRect".  
// Normally you might write "fillRect" in one line like so...
// ctx.fillRect(50 ,50, 100, 200);

// ...but let's write a staggered version so we can explain each argument...

ctx.fillRect( 50,	// The X position of the upper left corner.
			  50,	// The Y position of the upper left corner.
              200,	// The WIDTH of the rectangle shape.
              100	// The HEIGHT of the rectangle shape.
              );

// And that's it!  This method doesn't need you to define color information
// because JavaScript will automatically use the most recently defined "fill
// style" for the same context you are drawing to.

// Let's look at the results...



// Notice how all of thse property assignments are referencing the context in
// dot notation?  The format almost always follows the same format...

// 			context variable  ->  period  ->  method name

// Keep in mind almost all drawing functions will do this.

// Now let's add another type of rectangle.

// Many canvas drawing functions have "stroke" methods associated with them.
// For the rectangle object, there is a specific method called "strokeRect" that
// works as follows (let's also make a different rectangle while we're at it to
// show the difference).

ctx.strokeRect(300, 25, 200, 100);

// "strokeRect" uses the same exact argument structure as "fillRect".  Had we
// made the values eaxtly the same as the previous "fillRect" method then the
// outline would have appeared directly over the light blue rectangle.

Canvas Drawing Operations

Now that we've seen the structure of drawing to a canvas object let's look at the types of shapes that we can draw with the various inherent methods.

Arcs

We'll walk through the code and add one shape at a time. Let's begin with circles curves.



// On top of your basic rectangle shapes we also have the ability to draw 
// circles to the canvas.  This is done using the "arc" method.  JavaScript uses
// arcs to draw circles because a fully curved line, or arc, is simply a 
// circular shape.  Hence a "circle" shape would be redundant while "arc" is
// available.

// To make a full circle use arc with the following arguments...

ctx.arc( 50,            // The X POSITION of the CENTER of the arc.
		 50,            // The Y POSITION of the CENTER of the arc.
         50,            // The RADIUS of the arc.
		 0,             // The STARTING ANGLE of the drawn arc.
         2 * Math.PI    // The ENDING ANGLE of the drawn arc.
         );
            
// If you're not familiar with te geometry of circle that last parameter of the 
// method might throw you.  

// Basically the circumference paremeters define the starting and ending point
// of the drawin line around the arc.  A value of "0" is considered to be the
// rightmost point on the circle edge.  The equation "2 * Math.PI" is a fancy
// way of writing a full curve of 360 degrees.  Since it uses the constant of PI
// it will be more exact than most methods.

// We can't just write "360" because ARCS ARE NOT MEASURED IN DEGREES.

// Arcs on canvas objects are measured in "radians".  We are not going to go
// into what that is at this time as it is tangential to our subject.

// If we want a quick and dirty way of converting degrees to radians we can use 
// the constant "0.0174533".

// For instance...

// 45  degrees times 0.0174533 = 0.78539 radians.
// 90  degrees times 0.0174533 = 1.57080 radians.
// 180 degrees times 0.0174533 = 3.14159 radians.
// 270 degrees times 0.0174533 = 4.71239 radians.

// In other words if you want to measure things in degrees just make sure you're
// multiplying your degrees by that figure.

// There's one more thing we need to do before out circle will appear though.
// Since we are not making a filled circle (yet), we need to draw the circle

ctx.stroke();




// To show another example of how the arc method works let's go ahead and add
// two more circles, but this time using different starting and ending angle 
// parameters.

// For the first addition we'll draw only 3/4's of the circle.
// For this circle let's show degrees converted to radians using the constant
// described above.

ctx.arc( 150, 100, 50, 0.78539, 5.49778 );           
ctx.stroke();

// For the second addition we'll draw only half of the circle.
// For this circle we'll use the Math.PI constant and show how with radians you
// can also just use multiples of "0.5" to describe quarter circle turns.
// (so 0.5 to 1.5 will be equivalent to 180 degrees)

ctx.arc( 250, 150, 50, 0.5 * Math.PI, 1.5 * Math.PI );     
ctx.stroke();

BUT WAIT! What the heck is that??? The lines forming the outer arcs themselves seem to be drawing correctly but there are extra lines here. The straight lines you see connecting each circle might be unexpected to you but there's a fairly simple, and good, reason for this.

If you want to draw more complex shapes using code it can sometimes actually be bothersome to draw try doing that with primitive shapes. For complex shapes you'll just want to define your own lines and curves and of course you'll want those lines and curves to be connected end to end.

Because of that we need look at drawing separate strokes on a canvas object as akin to picking up a pen from a piece of paper, moving it, and then placing it back down.

There are two ways we can go about doing this.

The first will involve a method called "beginPath".



// Let's edit the same code we had above.  Remember this is all after the
// initial creation of canvas and context references as well.

// By invoking "beginPath" at the start of each shape definition we can tell the
// canvas we DO NOT wish to continue form the previous path.  

ctx.beginPath();
ctx.arc( 50, 50, 50, 0, 2 * Math.PI );
ctx.stroke();

ctx.beginPath();
ctx.arc( 150, 100, 50, 0.78539, 5.49778 );   
ctx.stroke();

ctx.beginPath();
ctx.arc( 250, 150, 50, 0.5 * Math.PI, 1.5 * Math.PI );   
ctx.stroke();

The other way we can break up strokes drawn to our canvas object is called, not coincidentally, "moveTo". But this is a function more useful in a setting where you are actually defining the shape with lines and curves.

Lines and Curves

Adding lines and and curves to canvas objects will make use of a few different methods. Primarily "lineTo", "moveTo", "bezierCurveTo", "quadraticCurveTo", and "closePath".

While looking at this example try to be aware that we are not simply drawing different lines from one point to another but that we are drawing one continuous line, until we instruct JavaScript to do otherwise, with different turns and direction changes.



////////////////////////////////////////////////////////////////////////////////
// Lines

// Here we'll draw a simple box at the bottom of the canvas.

// First we'll position the beginning of the stroke.
// This it the upper left point in our square.
ctx.moveTo( 340, 340 );

// We then stroke directly downwards.
ctx.lineTo( 340, 380 );

// ...Directly to the right.
ctx.lineTo( 380, 380 );

// And directly up.
ctx.lineTo( 380, 340 );

// We *could* use another "lineTo" to draw a line to the starting
// position, but why do that when we can simply invoke "closePath".
ctx.closePath();

// We can then draw the stroke by invoking "stroke()".
ctx.stroke();



////////////////////////////////////////////////////////////////////////////////
// Curves

// Let's practice curves by drawing a single question mark shape.
// This is a good glyph because it will include straight lines, arcs, and
// bezier curves all at once.

// Begin the canvas drawing process by creating the standard references...

var canvas = document.getElementById("canvas_name");
canvas.width = 700;
canvas.height = 400;
var ctx = canvas.getContext("2d");

// We'll change the default line thickness to make it more apparent.
ctx.lineWidth = 4;

// First we draw a simple square for the bottom of the glyph.
// This is the same box as seen in the previous image.

ctx.moveTo( 340, 300 );
ctx.lineTo( 340, 340 );
ctx.lineTo( 380, 340 );
ctx.lineTo( 380, 300 );
ctx.closePath();

// Now we draw the upper half of the glyph.

// First let's reposition the drawing point to the lower left of the curved part
// of the question mark we're drawing.
ctx.moveTo( 340, 260 );

// Make the straight line along the bottom of it to the right.
ctx.lineTo( 380, 260 );

// Here's the first time we'll use a "bezierCurveTo" to draw the right side of 
// the s-curve going up the middle.
ctx.bezierCurveTo( 380, 200, 	// First curve point.
				   420, 200, 	// Secon curve point.
				   430, 140 	// Line end point.
                   );

// Draw a half circle arc on the top side of the top curve.
ctx.arc( 360, 140, 70, 0, 1.0 * Math.PI, true  );

// Draw a straight line for the curved end of the glyph.
ctx.lineTo( 330, 140 );

// Draw a half circle arc on the underside of the top curve.
ctx.arc( 360, 140, 30, 1.0 * Math.PI, 0 );

// Draw the left side of the s-curve going up the middle.
ctx.bezierCurveTo( 390, 180, 
				   340, 180, 
				   340, 260 );

// Finally invoke "stroke" one more time to finish the glyph.
ctx.stroke();

// Just to illustrate how complex shapes can be easily filled, let's go ahead
// and choose a color with "fillStyle" and fill the shape with "fill()".
ctx.fillStyle = "lightgrey";
ctx.fill();

Blitting

You may recall hearing the word "blitting" before. It's a technique that can be used by CSS to show only a part of an image within an HTML element on your page.

Click this sentence to see the original page relating to blitting in CSS (it can be found at the bottom of the page).

Let's pretend we are starting a new canvas project instead of continuing from the previous shape examples. You'll find that to copy bitmaps the process is much the same.

The primary difference will be our use of the "drawImage" method. The arguments for this method will be explained alongside the method in the comments.

But! To use a "drawImage" method you must have a source object from which to take the image information you want to copy. This can be either an "img" element on the web page itself or else another canvas object with an already assigned image link.

The image to the right will be the SOURCE image we are drawing FROM.

Let's also include the pertinent HTML in this example from the beginning to see one way blitting be implemented.



<html>
<header>
<style>

#canvas_name {
	position: relative;
    margin-left: 20px;
    margin-top:  40px;
    
    background-color:pink;
    outline:1px solid black;
}

/*
Within our CSS we can set the display property of our image element to "none".
This will allow us to let the document load the image we'll be using itself
right alongside the loading of the rest of the page - but without having the
image be actually rendered on the page.
*/
#source_image {
	display:none;
}

</style>
</header>
<body>

<!-- Since the "img" will not be shown we can actually place this element
anywhere within the page HTML -->
<img id="source_image" src="image.png"/>

<canvas id="canvas_name"></canvas>

</body>
</html>
<script>

// Canvas editing code will go here.

</script>

And now for the script... (remember this should go AFTER all pertinent references).



////////////////////////////////////////////////////////////////////////////////
// Blitting

// First we create references to our needed objects as normal.
var canvas = document.getElementById("canvas_name");
canvas.width = 700;
canvas.height = 400;
var ctx = canvas.getContext("2d");

// We will also need to create a reference to our source image.  In this
// particular implementation we're just goin to reference the existing "img" tag
// we've already placed on the page.  It's just a normal "getElementById".

var source = document.getElementById("source_image");

// And then will be ready to call the image drawing function.

ctx.drawImage( 
        source,         // <img> element or var reference to use as a SOURCE.
        0,              // Source rect X COORDINATE.
        0,              // Source rect Y COORDINATE.
        400,            // Source rect WIDTH.
        400,            // Source rect HEIGHT.
        50,             // Target rect X COORDINATE.
        50,             // Target rect Y COORDINATE.
        200,            // Target rect X WIDTH.
        200             // Target rect Y HEIGHT.
        );

// Let's use the draw function twice to further illustrate how the second,
// third, fourth, and fifth arguments can grab a small piece of the original
// image to draw, and also how the last two arguments can resize that small 
// piece to a different scale than it was in the original image.  This is an
// important concept in ALL programming related to drawing images to a user's
// computer screen.

ctx.drawImage( source, 100, 100, 200, 200, 300, 50, 300, 300 );

// As you can see by the numbers chosen, the first "drawImage" will place the
// blitted image on the left side of the canvas, while the second "drawImage"
// above will place a larger, zoomed in, version of the image on the right side
// of the canvas.

Here are a few miscellaneous qualities of canvas objects you should keep in mind.

  • Canvas objects are actually images generated by the browser. This means that at any time the user can Right-Click and select "Save image as..." to save the image to their local disk.
  • Most browsers will save canvas frames as .png files. This means that if you have not filled the ENTIRE canvas then the unfilled parts will appear as transparent pixels in the saved file.
  • If you write code that allows interactivity with the canvas object the reported position of your mouse may change when and if you change the zoom level within your browser (the internal mouse position will be scaled accordingly).

In Summary

Let's summarize all of the methods that we've talked about on this page. There have been quite a few.

function description
beginPath Informs the browser that you wish to start a new path. If a stroke is currently being drawn it will be broken between the previous location and the next location defined.
closePath Connects the current position of the stroke to the first position defined after the most recent "beginPath".
moveTo Move the end point of a stroke being drawn to a new point without connecting the two.
lineTo Draw a line form the current end point to the new position.
bezierCurveTo Draw a curved line based on "control points" from the current position.
arc Used to draw partial, or full, circles around a single origin point.
stroke The actual draw call that traces a line defined by methods such as "lineTo" and "arc". Not needed for methods that already use the word "stroke".
Fill Will fill the current stroke shape from the most recent point to the first point ( either since a beginPath if one has been used or the first stroke position if no beginPath was used).
fillRect Fills a rectangular shape on the canvas.
drawImage Draws part or all of a source image to a canvas object.