Sketch appeal: Using HTML5 Canvas
In this tutorial, Fr
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