Get crafty

Sketch appeal: Using HTML5 Canvas

In the past, when talking about drawing graphics, creating animations, or even making photo composition, it was all about Flash, or a good old animated GIF if it wasn’t dynamic. Today the <canvas> element gives us the opportunity to draw graphics via JavaScript. In this article, originally published in the September issue of JAX Magazine, Frédéric Harper shows us how it's done.

The canvas

The <canvas> element gives you access to some context, 2D or 3D, that you can draw on it. Basically, it gives you a rectangular area where you can draw on it. Let’s focus on the 2D context as it’s the most popular, and implemented one.

Browser support

Whenever you want to use latest features of HTML5, a good thing to do is to see how broad the feature or the element you want to use is implemented in the browsers. My favorite site for that is "When Can I use" [1]. It’s always up to date, and from my point of view, the best site out there to check about support for HTML, CSS, JavaScript, and other features.

The <canvas> element is supported in all recent versions of major browsers on the desktop, but also on mobile ones. For most browsers, the basic support is there for a long time, so I would commit myself by writing that you can use it without any problem, except if you need to support older version of Internet Explorer (below 9). For older browsers, there is probably some polyfill out there, but I won’t suggest one as I never had to use one. In that situation, Google [3] is your best friend or Modernizr [4] usually have a good list [5] for this.

Talking about Modernizr, it’s always a good idea to use this JavaScript library when you are using HTML5 or CSS3. You only need to import the JavaScript file and check if <canvas> is supported by doing a simple if statement:

if (Modernizr.canvas) {
    //Do what you have to do
}
else {
    //Do something else, a fallback
}

Drawing shapes
The first step is obviously to add the element to our HTML code.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <canvas id="myCanvas" width="600px" height="400px"></canvas>
        <script type="text/javascript" src="js/scripts.js"></script>
    </body>
</html>

Note that we set the width and height directly in the HTML page, and it’s what we wanted. Usually we use CSS to do this, but when it comes to <canvas> element, it doesn’t do what you would like to do when it comes for the size of the canvas: it does a zoom on the canvas, and what you want is to set the dimensions. Another way would have been to use javascript to set the width, and height of it. Now, you have your canvas, but it’s a boring one as it’s empty, and does nothing! Let’s create something a little more exciting by drawing stuff on it with our lovely Javascript.

(function() {
    "use strict";

    //Draw right at the beginning
    window.onload = function() {
        //We need to get the context first
        var ctx = document.querySelector("#myCanvas").getContext("2d");

        //Let's draw a full blue rectangle
        ctx.fillStyle = "#0000FF";
        ctx.fillRect(30, 30, 80, 140);

        //Now a red circle, with a green stroke
        ctx.fillStyle = "#FF0000";
        ctx.beginPath();
        ctx.arc(140, 160, 70, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
        ctx.strokeStyle = "green";
        ctx.lineWidth = 6;
        ctx.stroke();

        //We can also make any other forms using lines, like a yellow triangle
        ctx.fillStyle = "rgb(255, 255, 0)";
        ctx.beginPath();
        ctx.moveTo(150, 170);
        ctx.lineTo(200,200);
        ctx.lineTo(120,250);
        ctx.closePath();
        ctx.fill();

        //Let's add some text
        ctx.fillStyle = "black";
        ctx.font = "bold 45pt Calibri";
        ctx.fillText('Hello World', 150, 100); 
    }
})();

Figure 2: the code running in the browser

Let’s pick apart the code below that made this amazing piece of art.

//We need to get the context first
var ctx = document.querySelector("#myCanvas").getContext("2d");

Firstly, without the 2d context, nothing would have been possible; it's why we use the getContext function to get… the context.

//Let's draw a full blue rectangle
ctx.fillStyle = "#0000FF";
ctx.fillRect(30, 30, 80, 140);

Using the context we got before, we want to create a blue rectangle. The default fill color is black, so we need to set it to blue, and we can use the hexadecimal value of blue to make it happen. After we set the color, we can now draw the rectangle by using the function fillRect, and specifying the x, y, width, and height of the rectangle.

//Now a red circle, with a green stroke
ctx.fillStyle = "#FF0000";
ctx.beginPath();
ctx.arc(140, 160, 70, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.strokeStyle = "green";
ctx.lineWidth = 6;
ctx.stroke();

Now let’s build the red circle with a green stroke. You can see now that I need to create a path that will be drawn on the context, by starting the process with the function beginPath, and close the path with closePath. Within the path, will use the arc function as there is no circle function. We’ll define the center of the arc (x, y), the radius, the start angle (in radian), and the end angle (in radian too). In our example, we use PI multiple by 2 to make a full circle. As for the stroke, we need to define the width of the line with the properties lineWidth, and ask the context to draw it by using the function stroke. Note that for the strokeStyle, I used the name of the color you can usually use in your CSS. It’s good for fillStyle too.

//We can also make any other forms using lines, like a yellow triangle
ctx.fillStyle = "rgb(255, 255, 0)";
ctx.beginPath();
ctx.moveTo(150, 170);
ctx.lineTo(200,200);
ctx.lineTo(120,250);
ctx.closePath();
ctx.fill();

Now let’s draw something a little more complex by using a path also. You can build anything you want from something more known as a triangle, to something else proper to some abstract art. In this example, we want to build a triangle. Look at my fillStyle value, I used the RGB value of yellow: again, it’s just another way to define the color. For the code of this path, you can imagine an invisible cursor. First step, let’s move the cursor to the start point by using the function moveTo. From that specific point, we’ll draw a line to the coordinate 200, 200. At the moment, it’s important to know that because I used lineTo, I need at least another point somewhere to make the form. I’ll add another line, and when I’ll call the fill function, because I closed the path, we’ll have a beautiful yellow rectangle.

//Let's add some text
ctx.fillStyle = "black";
ctx.font = "bold 45pt Calibri";
ctx.fillText('Hello World', 150, 100); 

Last, but not least, I can write, or should I say draw, some text on the canvas. You still have to set the fillStyle if you don’t want the default one, or the last one used in this context (in our case, yellow). Optionally, you can set the font also with a type, size, and a font. To make the magic happen, just use fillText function by passing three values: the text itself, the x, and the y of where you want the text to start on the canvas.

Of course, there is a lot more you can draw on canvas, like images or play with opacity, image pattern, gradient, and more. One thing to notice is the order elements has been drawn: exactly in the same order that the javascript has been executed. You can see that the triangle is over the circle that is over the blue rectangle.

Transformation

If it was only about drawing stuff, the <canvas> element wouldn’t have been so exciting. You can also apply transformation to the canvas, and it’s where, from my own opinion, the real power of the canvas resides. From that point, you can also create animations: think about all the HTML games you like to play, they are done using the canvas element. In the past, Flash or Java would have been (mostly) our only hope.

You will mostly use these functions: scale, rotate, translate, and transform. Let’s play with our previous code, and do some transformations to it.

Figure 3: our previous HTML page with some transformation applied 

You can clearly see that the drawings we did aren’t the same in this screenshot. Let’s see the new JavaScript code:

(function() {
    "use strict";

    //Draw right at the beginning
    window.onload = function() {
        //We need to get the context first
        var ctx = document.querySelector("#myCanvas").getContext("2d");

        //Translate the drawing will do
        ctx.translate(100, 100);

        //Let's draw a full blue rectangle
        ctx.fillStyle = "#0000FF";
        ctx.fillRect(30, 30, 80, 140);

        //Now a red circle, with a green stroke
        ctx.fillStyle = "#FF0000";
        ctx.beginPath();
        ctx.arc(140, 160, 70, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
        ctx.strokeStyle = "green";
        ctx.lineWidth = 6;
        ctx.stroke();

        //Rotate the triangle, and the text of 15 degrees
        ctx.rotate(15 * Math.PI * 2 / 360);

        //We can also make any other forms using lines, like a yellow triangle
        ctx.fillStyle = "rgb(255, 255, 0)";
        ctx.beginPath();
        ctx.moveTo(150, 170);
        ctx.lineTo(200,200);
        ctx.lineTo(120,250);
        ctx.closePath();
        ctx.fill();

        //Scale the text
        ctx.scale(1.2, 1.2);

        //Let's add some text
        ctx.fillStyle = "black";
        ctx.font = "bold 45pt Calibri";
        ctx.fillText('Hello World', 150, 100); 
    }
})();

The first thing to notice is that as with the drawing, the transformations are applied on the context at the time their lines are interpreted by the JavaScript engine. In that situation, the context will change, and the next drawing, and transformation will be affected. Let’s check the code we added:

//Translate the drawing will do
ctx.translate(100, 100);

Firstly, we move everything from 100 pixels to the right, and 100 pixels down. It has moved every draw we’ve down after as it was the first transformation we did, before even the first draw.

//Rotate the triangle, and the text of 15 degrees
ctx.rotate(15 * Math.PI * 2 / 360);

The rotation is really simple as you only need to call the rotate function, and give the rotation in radians. In that case, I did a rotation clockwise of 15 degrees. Math.PI * 2 / 360 is the calculation you need to do to go from degrees to radians, and since it’s easy for me to work in degree, I prefer to put this in my code. I would have been able also to do an anticlockwise rotation by giving a negative degree.

//Scale the text
ctx.scale(1.2, 1.2);

Last but not least, we scale the text by 20% using the scale function. One hundred percent is equal to 1 when you use this function. I would have been able to scale down by using numbers lower than 1. In that situation, I scaled the width, and the height with the same ratio. 

You would also have been able to use the transform function, which gives you the opportunity to scale, rotate, move, and skew the current context in the same function. From that point, you would be able to create animation by using different techniques. The animation is a topic by itself, as there are many things to take consider, and many pitfalls you don’t want to take if you want your application, game or website to be successful.

Have some fun 

It would have been easy to create a series of article on the <canvas> element as it’s impossible to write about all the complexity of that amazing addition to the HTML standard. Henceforth,  you can read the W3C documentation (it’s not made for Web developers, but for vendors who want to implement the standard) on the HTML Canvas 2D Context [6] or find more friendly documentation about it on the Mozilla Developer Network [7] Canvas page [8]. You can also play with the code of this article, which is available to clone, fork, modify, and play with on GitHub [9]. Now open your preferred text editor, and play with the <canvas> element!

In the IT world for more than 10 years, Frédéric Harper started as a developer working with different technologies focusing on Web, and mobile development. One day, Frédéric got a revelation, and decided to use his social skills to become an Evangelist. He spent a few years showing the Openness of Microsoft talking about Open Source, Web standards, and Interoperability. Now, as a Senior Technical Evangelist at Mozilla, Fred shares his passion about the Open Web, and help developers be successful with Firefox OS. Experienced speaker, t-shirts wearer, long-time blogger, passionate hugger, and HTML5 lover, Fred lives in Montréal, and speak Frenglish. Always conscious about the importance of unicorns, and gnomes, you can read about these topics, and other thoughts at outofcomfortzone.net.

References

  • [1] http://caniuse.com/

  • [2] http://andismith.github.io/caniuse-widget/

  • [3] http://lmgtfy.com/?q=canvas+polyfill

  • [4] http://modernizr.com/

  • [5] https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills

  • [6] http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/

  • [7] https://developer.mozilla.org

  • [8] https://developer.mozilla.org/en/docs/HTML/Canvas

  • [9] https://github.com/fharper/WebPHPmagazine-HTML5_Now_series-The_Canvas

Image by jen_marq

Frédéric  Harper
Frédéric Harper

What do you think?

JAX Magazine - 2014 - 05 Exclucively for iPad users JAX Magazine on Android

Comments

Latest opinions