Get crafty

Sketch appeal: Using HTML5 Canvas

FrdricHarper
palette

In this tutorial, Frédéric Harper gives us a comprehensive HTML5 Canvas workout

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

Author
Comments
comments powered by Disqus