DWUser.com

Empowering Web Creativity

Back to Education Center Home:  Go Back        Font size:  Smaller  Larger         Font weight:  Lighter  Heavier 

Watch Out, da Vinci:
Intro to Drawing with the HTML5 Canvas Element

by Sue Smith

Your first masterpiece drawing

The ability to create drawings dynamically using JavaScript has made the canvas element one of the most talked-about features in HTML5. With canvas you can script complex 2D and 3D drawings as the user interacts with the page, even including animations. Although the possibilities offered by the canvas element are attractive to many designers and developers, getting started with it can be a bit of a challenge, particularly if you have little experience in JavaScript. However, the functions involved are accessible even to beginners, as I will demonstrate in this tutorial.

To explore the basics of creating drawings in HTML5, we will create a few canvas elements and implement some JavaScript code to draw shapes, customizing fill/ stroke styles and using randomness to mix things up a little. I will also demonstrate importing an image file to display within a canvas, then drawing on top of it. Finally, I will show what you can do with transformations in your canvas elements, using a simple translation effect.

Check out the demo to see where we're headed.

If you're new to JavaScript, you might want to open up book #4 in Keith's article, 7 Free eBooks that Should Line Every Web Professional's Digital Bookshelf, to use as a reference as you follow along with this article.

Set Up an HTML5 Page

To begin, create a new HTML5 page using the following outline:

<!DOCTYPE HTML>
<html>
<head>
</head>
<body>

</body>
</html>

A Quick Word on Compatibility...

Unfortunately, IE didn't get in on the canvas element fun until version 9. If you have many visitors using IE8, you'll need to ask them to upgrade or provide alternate fallback content. However, use of the canvas element is becoming more practical by the day, as over 80% of the world is now using a compatible browser.

Create a Canvas

In the body section of your new page, add a canvas element as follows:

<canvas id="moonPic" width="500" height="400">
   <!--default content for fallback in case no canvas support-->
   Whoops! Your browser doesn't support the canvas element...
</canvas>

The first picture we create is going to be the night sky with a full moon, so we give the element "moonPic" as its ID. We alse set the width and height, which you will do whenever you create a canvas element. The canvas drawing functions use a system of x and y coordinates.The point at the top-left of this canvas has an x coordinate of zero and also a y coordinate of zero. The bottom-right point is 499, 399 (x, y) since the area is 500 wide and 400 in height. (In case you're mind is wandering back to high school algebra class, this is just a vertical flip of the good ol' Cartesian coordinate plane.)

Between the opening and closing tags, you can place any content you want to appear if the user's browser does not support canvas, such as an alternative static image file or informative message as above. You can optionally use CSS to apply a border to your canvas element:

<style type="text/css">
canvas {
   border: 1px dashed #999999;
}
</style>

Add a Script

The work involved in drawing with the canvas is implemented in JavaScript, so add a script section after your canvas as follows:

<script type="text/javascript">

</script>

Note: We're placing our JavaScript within the body, but you could alternatively place a function in the page head or an external script, executing it on an event such as the page content loading.

Before we start drawing, we need to retrieve the context from the canvas element, so add the following inside your script tag:

var moonCanvas = document.getElementById("moonPic");
var moonContext = moonCanvas.getContext("2d");

This is what your canvas scripts will generally start with – the context of a canvas provides most of its drawing functions.

Color the Sky

Let's start by coloring the night sky. This is going to be a blue gradient that will fill the entire background of the canvas. Begin by defining the gradient:

// Define the gradient
var skyGradient = moonContext.createLinearGradient(0, 0, 0, 400);
// Add colors
skyGradient.addColorStop(0, "#000033");
skyGradient.addColorStop(1, "#000099");

The first line here creates a linear gradient, defining the x and y start and end points – the parameter values are the x and y coordinates of the start point followed by the x and y coordinates for the end point. In this case the gradient will run straight down from top to bottom, covering the entire canvas background. The last two lines add two color stops to the gradient. The color stops are at the very start and very end of the gradient, with dark blue running down into lighter blue. Now, fill the canvas with this gradient:

moonContext.fillStyle = skyGradient;
moonContext.fillRect(0, 0, 500, 400);

We instruct the context to use the gradient as fill, then apply it to a rectangle occupying the full available space inside the element – the first two parameters are the coordinates for the start point and the second two are the width and height:

sky background

Add Some Stars

Let's add some stars. Each one can be a simple white rectangle 1 pixel by 1 pixel in size, yielding a little dot of white light. We will use the fillRect method again, but this time we will also exploit some JavaScript utilities to add a dynamic effect to the image. First set the fill style to white:

moonContext.fillStyle = "#ffffff";

Now enter a loop, in which we will add 200 stars to the picture:

for (var i=0; i<200; i++) { 
   // Looped contents will go here
}

If you aren't familiar with loops, don't worry; all you need to know is that this means the code inside the loop will execute 200 times. Inside the loop (before the closing } bracket) add code to choose x and y coordinates for a star at random:

var xCo = Math.floor(Math.random() * 500); //min 0 max 499
var yCo = Math.floor(Math.random() * 400); //min 0 max 399

If you haven't used random functions, again, don't be intimidated by this code; it's actually very simple. The numbers we have used in the function mean that each time the loop iterates, we will get an x coordinate between zero (inclusive) and 500 (exclusive) and a y coordinate between zero and 400, making the coordinates indicate a point within the dimensions of the canvas.

Still inside the loop, draw a 1 pixel rectangle at the random coordinates:

moonContext.fillRect(xCo, yCo, 1, 1);

If you save and open your page now, you should see the stars. Refresh the page to see that the random coordinates are generated again each time the page is viewed and the canvas rendered:

Draw the Moon

Notice that each element we draw is added on top of the existing image, so we always start at the background and work towards the foreground. Let's add a final element to the picture – the moon. After the loop you created for the stars, define another gradient, this time a radial one:

var moonGradient = moonContext.createRadialGradient(370, 80, 10, 350, 100, 50);

Radial gradients are a little more complex than their linear counterparts. The parameter values we supply represent two circles, one at the center of the gradient and one at its outside edge. The first two values represent the x and y coordinates at the center of the inner circle. The third value is the radius of this inner circle. The final three values indicate the central point (x and y) and radius of the outer circle. This will become a little clearer when we draw the circle, but here's a diagram to illustrate things:

Radial gradient diagram

Next, define the gradient colors:

moonGradient.addColorStop(0.3, "#ffffff");
moonGradient.addColorStop(0.9, "#ffff66");

This is similar to the code in which we set the linear gradient colors, but with white and yellow this time. Notice that these color stops indicate points that are not at the start and end of the gradient fill – this will make areas of solid color at the center and outer points of the shape, with the gradient between them. Set this gradient as the fill:

moonContext.fillStyle = moonGradient;

Now we need to define a circle path, so start as follows:

moonContext.beginPath();

We use an arc to define the circle:

moonContext.arc(350, 100, 50, 0, Math.PI*2);

The parameter values here represent the x and y coordinates for the central point of the circle, the radius, and finally two angles indicating where to start and finish the arc – for a circle this means going from zero to Pi multiplied by 2. (It's high school deja vu again, this time from trig class!) Don't worry at all if you don't understand the math here; it really isn't necessary – you can simply copy the code. Now apply the gradient fill to the circle:

moonContext.fill();

To keep things tidy close the path:

moonContext.closePath();

If you look at the line in which you define the radial gradient and the line in which you define the arc, you will gain a better understanding of the details. The circle as a whole has a radius of 50 with a central point of (350, 100). The outer circle of the radial gradient indicates the whole of this shape, while the inner circle indicates a portion of it (with a radius of 10 and a central point slightly up and to the right). Look again at the grid diagram above to see what I mean.

Open the page in your browser to see the result:

Not quite a da Vinci, but a nice start for your first drawing!

Import an Image

Now let's create another canvas and import an external image so that we can draw on top of it. Add a new canvas element using the same technique as before, but with different dimensions:

<canvas id="flowerPic" width="300" height="400">
   Whoops! Your browser doesn't support the canvas element...
</canvas>

We will be importing the following image, which is 300 by 400 pixels – the same as the canvas:

flowers

Add another script section after the new canvas:

<script type="text/javascript">

</script>

Start the script using the same technique as before:

var flowerCanvas = document.getElementById("flowerPic"); // this code always must appear after the canvas definition
var flowerContext = flowerCanvas.getContext("2d");

Now create an image object:

var flowerImage = new Image();

Define what should happen when the image loads (we'll load it momentarily):

flowerImage.onload = function(){
   // Draw the image into the canvas
   flowerContext.drawImage(flowerImage, 0, 0);
};

The content of this function will execute when the image file has been loaded. We instruct the context to draw the image from the top-left corner of the canvas (coordinates 0,0) so that it will fill the whole available space.

Now, we will draw a circle outline on top of the picture – add the following inside the function, after the drawImage line:

   // Draw a circle - define stroke
   flowerContext.strokeStyle = "#ffff33";
   flowerContext.lineWidth = "2";
   // Define circle at coordinates (205, 180) with radius=50 
   flowerContext.beginPath();
   flowerContext.arc(205, 180, 50, 0, Math.PI*2, true);
   // Apply stroke
   flowerContext.stroke();
   flowerContext.closePath();

We use the same technique as we used for the moon shape, but this time we draw a stroke rather than a fill, setting the stroke style and width. After the end of the current function (after the }; code), set the image's source to begin loading it:

flowerImage.src = "images/flowers.jpg";

Alter this to suit your own file if necessary. Load the page to see the effect:

The circle has, of course, been chosen to appear on top of a particular section of the image.

Apply Transformations

Let's finish by looking at a final, slightly more advanced example with a transformation applied to it. We will spend less time going through the details of the code here, focusing instead on the big picture of what is possible with the canvas element. So don't worry if you find some of the scripting confusing; just follow along and enjoy the possibilites! Start by creating another canvas and script:

<canvas id="transPic" width="400" height="300">
   Whoops! Your browser doesn't support the canvas element...
</canvas> 

<script type="text/javascript">

</script>

Start the script in the usual way:

var transCanvas = document.getElementById("transPic");
var transContext = transCanvas.getContext("2d");

Add a background gradient as before, this time going diagonally across and down rather than straight down:

var dayGradient = transContext.createLinearGradient(0, 0, 400, 300);
dayGradient.addColorStop(0, "#0033ff");
dayGradient.addColorStop(1, "#0000cc");
transContext.fillStyle = dayGradient;
transContext.fillRect(0, 0, 400, 300);

Now add a circle to represent the sun, with a yellow fill and white stroke:

transContext.beginPath();
// Define a small circle at (25,25)
transContext.arc(25, 25, 20, 0, Math.PI*2, true);
// Fill it
transContext.fillStyle = "#ffff00";
transContext.fill();
// Stroke it
transContext.strokeStyle = "#ffffff";
transContext.stroke();

When you script with the canvas, you can use transformations such as translation, to move the point of drawing along the x and y axes, as in the following example code:

transContext.translate(50, 100); //move 50 right and 100 down

We are going to use a loop to redraw the circle multiple times. Each time, we will translate the point of drawing to the right and down the image, altering the opacity as we go:

// Redraw with translate
for (var j=2; j<17; j++) 
{
   // Move across and down
   transContext.translate(j*2, j); //translate(x, y)
   // Define circle arc
   transContext.beginPath();
   transContext.arc(25, 25, 20, 0, Math.PI*2, true);
   // Alter alpha (opacity) with relative value.  Alpha is between 0 and 1; we want it to become less and less.
   transContext.globalAlpha = 1-((j-1)/15); 
   // Apply fill
   transContext.fill();
   // Use full alpha for stroke
   transContext.globalAlpha=1;
   transContext.stroke();
}

Take a moment to look over this code, as it isn't as complex as you may think. The loop will iterate 15 times, redrawing the circle each time. Every time the loop executes we move right and down using the translate method, increasing the amount we move along the axes incrementally by using the loop counter variable to calculate the x and y values. We use the exact same code as we used for the first circle to define the arc, but each circle is drawn at a different location because of the translation effect. We set the alpha level for the fill to decrease each time the loop iterates and apply the white lines with full opacity. The reason we start the loop counter at 2 is so that we can use it more easily in the translation and alpha effects – if it started at zero or 1 this wouldn't have the desired effect of gradually increasing the translation and decreasing the opacity.

Here's the final result:

transformation applied

Why Is This So Important?

As great as canvas drawing is, you might be asking yourself: "What's the big deal? I can do all this in Photoshop in about 30 seconds!"  That's completely true, and if you're trying to create static images you should stick with Photoshop. What makes canvas drawing so special is that it's all dynamic, happening at the instant you use a script to do the drawing. This means you can create interactive graphics (e.g. charting), animations and much more, whenever you need it, taking into account changing data and/or user input. The dynamic nature of canvas drawing opens up a wide world of potential applications.

Conclusion

A closing reminder: As you have fun with this HTML5 feature, make sure you include alternatives for users without supporting browsers if you're providing content that's mission-critical. Fortunately, we're rapidly moving towards full browser adoption – we just have to wait a little longer on IE8.

In this tutorial, you've learned the basics of scripting your own drawings using the canvas tag in HTML5. Beyond what we covered, there's even more available – such as support for text, bezier curves and complex shapes. While we focused on 2d drawing, support for 3d drawing is in the works too, so the possibilities are only going to expand.

Happy drawing!

Tell Others and Have Your Say

 
 
Customizable Google Maps Made Easy! Try EasyMapBuilder Now »
 
Log In
  Reset Password...
 
Why create an account?
  • Manage support tickets and purchases
  • Access to free extensions
  • Special discounts and offers
  • Access to member-only forums
Create Account
100% Spam-Free Guarantee
(Optional)
 

Use the following form to ask a question or submit a support request. An appropriate staff member will reply as soon as possible (usually within a few hours).
Contact Us / Create Support Ticket
 
To attach files, you must Sign Up or Log In.

You have no items in your basket.  Featured products:

XML Flash Slideshow v4 Flash Audio Kit for Dreamweaver

Home | Customer Satisfaction / Refund Policy | Privacy Policy | jQuery Slider | Top of Page

© 2003-2018 DWUser.com / Magnetic Marketing Corp.  All rights reserved.