Drawing images from a video stream

The drawImage(…) function can take a video element as its first parameter. The image that will be drawn is the one currently played by the video stream.

Online example at http://jsbin.com/dajena/3/edit

This example shows:

    • a <video> element on top, and four images drawn in a canvas below.
    • The images are drawn every XXX milliseconds using the setInterval(function, delay) method.
  1.    var video;
  2.    var canvas, ctx;
  3.    var angle = 0;
  4.  
  5. function init() {
  6.    video = document.getElementById(‘sourcevid’);
  7.    canvas = document.getElementById(‘myCanvas’);
  8.    ctx = canvas.getContext(‘2d’);
  9.  
  10.    setInterval(“processFrame()”, 25); // call processFrame each 25ms
  11. }
  12.  
  13. function processFrame() {
  14.     ctx.drawImage(video, 0, 0, 320, 180);

  15.     drawRotatingVideo(480, 90);

  16.     ctx.drawImage(video, 0, 180, 320, 180);
  17.     ctx.drawImage(video, 320, 180, 320, 180);
  18. }
  19.  
  20. function drawRotatingVideo(x, y) {
  21.      // Clear the zone at the top right quarter of the canvas
  22.     ctx.clearRect(320, 0, 320, 180);
  23.  
  24.     // We are going to change the coordinate system, save the context!
  25.     ctx.save();
  26.     // translate, rotate and recenter the image at its “real” center,
  27.     //not the top left corner
  28.     ctx.translate(x, y);
  29.     ctx.rotate(angle += 0.01); // rotate and increment the current angle
  30.     ctx.translate(-80, 45);
  31.  
  32.     ctx.drawImage(video, 0, 0, 160, 90);
  33.  
  34.     // restore the context
  35.     ctx.restore();
  36. }
  37. </head>
  38.  
  39. <body onload=init() >
  40. <p>This is a <video> element: </p>
  41. <video id=“sourcevid” autoplay=“true” loop=“true”>
  42. <sourcesrc=http://www.craftymind.com/factory/html5video/BigBuckBunny_640x360.mp4&#8221;
  43.          type=“video/mp4” />
  44. <sourcesrc=http://www.craftymind.com/factory/html5video/BigBuckBunny_640x360.ogv&#8221;
  45.          type=“video/ogg”/>
  46. </video>
  47. <p>This is a <canvas> element: </p>
  48. <canvas id=“myCanvas” width=“620” height=“360”></canvas>
  49. </body>

Drawing images

Basic example:

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4.  
  5.       window.onload = function() {
  6.         // It is necessary to wait for the web page to load before running this code.
  7.         var canvas = document.getElementById(“myCanvas”);
  8.         var context = canvas.getContext(“2d”);
  9.         var imageObj = new Image();
  10.         // Callback function called by the imageObj.src = …. line
  11.         //located after this function
  12.         imageObj.onload = function() {
  13.           // Draw the image only when we have the guarantee 
  14.           // that it has been loaded
  15.             context.drawImage(imageObj, 0, 0);
  16.          };
  17.  
  18.          // Calls the imageObj.onload function asynchronously
  19.          imageObj.src =
  20.           “http://www.w3.org/html/logo/downloads/HTML5_Logo_512.png&#8221;;
  21.      };
  22.    
  23. </head>
  24. <body>
  25.     <canvas id=“myCanvas” width=“512” height=“512”></canvas>
  26. </body>
  27. </html>

There are numerous variants of the drawImage(…) context method at line 17:

    • drawImage(img, x, y): draws the image at position x, y, keeping the original image size.
    • drawImage(img, x, y, sizeX, sizeY): same as before except that the image drawn is resized.
    • drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh): for drawing sub-images, (sx, sy, sw, sh) define the source rectangle, while dx, dy, dw, sh define the target rectangle. If these rectangles don’t have the same size, the source sub-image is resized.

EXAMPLE 2:

  1. var imageObj = new Image();
  2.  
  3. imageObj.onload = function() {
  4.    // Try commenting/uncommenting the following lines to see the
  5.    // effect of the different drawImage variants
  6.    // Original, big image
  7.    // context.drawImage(imageObj, 0, 10);
  8.    // Original image drawn with size = 100×100 pixels
  9.    context.drawImage(imageObj, 0, 10, 100, 100);
  10.    // with size = 150×150
  11.    context.drawImage(imageObj, 80, 10, 150, 150);
  12.    // with size = 200×200
  13.    context.drawImage(imageObj, 210, 10, 200, 200);
  14.  
  15.   // draw the sub image at 0, 0, width = 512, height = 100
  16.   // at position 100, 250, with a width of 256 and a height of 50
  17.   context.drawImage(imageObj, 0, 0, 512, 100, 100, 250, 256, 50);
  18. };
  19. imageObj.src = http://www.w3.org/html/logo/downloads/HTML5_Logo_512.png&#8221;;
  20. };

EXAMPLE 3: DRAW AN IMAGE DEFINED IN THE PAGE BY AN <IMG SRC=”…”>ELEMENT

  1. <body>
  2. <canvas id=“myCanvas” width=“512” height=“512”></canvas>
  3. <p>Original image as an <img> element:</p>
  4. <img id=“logo”
  5. src=http://fc07.deviantart.net/fs70/f/2013/149/b/8/texture_85_by_voyager168-d670m68.jpg&#8221;>
  6.      canvas = document.getElementById(“myCanvas”);
  7.      var ctx = canvas.getContext(“2d”);
  8.      var logo = document.querySelector(“#logo”);
  9.      ctx.drawImage(logo, 0, 0, 100, 100);
  10. </body>

Although you will find many examples on the Web that do it this way, they will only work most of the time with small images, or with images that are in the browser’s cache. Remember that you cannot draw an image that has not been fully loaded!

Best practice: only draw an image that is fully loaded, use
the
onload callback!

GOOD => the right way to do this is shown in this example: http://jsbin.com/faqedu/4/edit, that starts drawing only from the onload callback function:

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4.    var canvas, context;
  5.    window.onload = function() {
  6.       canvas = document.getElementById(“myCanvas”);
  7.       context = canvas.getContext(“2d”);
  8.  
  9.       draw();
  10.    };
  11.    function draw() {
  12.       var imageObj = document.querySelector(“#logo”);
  13.       console.log(“image is already loaded, we draw it!”);
  14.       context.drawImage(imageObj, 0, 10, 100, 100);
  15.    }
  16. </head>
  17. <body>
  18. <canvas id=“myCanvas” width=“512” height=“512”></canvas>
  19. </p>
  20. <img id=“logo” src=http://www.w3.org/html/logo/downloads/HTML5_Logo_512.png&#8221;>
  21. </body>
  22. </html>

Drawing rectangles – immediate drawing mode

EXAMPLE: DRAWING RECTANGLES IN IMMEDIATE MODE USING GOOD PRACTICE

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>Some rectangles drawn in immediate mode</title>
  5. <style>
  6.     #myCanvas {
  7.         border: 1px solid #9C9898;
  8.     }
  9. </style>
  10.     var canvas, ctx;
  11.  
  12.     window.onload = function () {
  13.        canvas = document.getElementById(‘myCanvas’);
  14.        ctx = canvas.getContext(‘2d’);
  15.  
  16.        // black rectangle, default color (black)
  17.        ctx.fillRect(10, 10, 100, 100);
  18.        // outlined rectangle, default color
  19.        ctx.strokeRect(150, 10, 100, 100);
  20.  
  21.        // outlined rectangle filled in red, outline blue
  22.        ctx.fillStyle = ‘red’;
  23.        ctx.strokeStyle = ‘lightBlue’;
  24.        ctx.lineWidth = 10;
  25.        ctx.fillRect(100, 150, 150, 150);
  26.        ctx.strokeRect(100, 150, 150, 150);
  27.  
  28.        // A function that automatizes previous drawing
  29.        var angle = Math.PI / 10;
  30.        drawFilledRectangle(300, 150, 150, 150, ‘pink’, ‘green’, 10, angle);
  31.        drawFilledRectangle(300, 150, 150, 150, ‘yellow’, ‘purple’, 10, angle +0.5);
  32. };
  33.  
  34. function drawFilledRectangle(x, y, w, h, fillColor, strokeColor, lw, angle) {
  35.     // GOOD PRACTICE: save if the function changes the context
  36.     // or coordinate
  37.     // system
  38.     ctx.save();
  39.  
  40.     // position coordinate system
  41.     ctx.translate(x, y);
  42.     ctx.rotate(angle);
  43.  
  44.     // set colors, line width…
  45.     ctx.lineWidth = lw;
  46.     ctx.fillStyle = fillColor;
  47.     ctx.strokeStyle = strokeColor;
  48.  
  49.     // draw at 0, 0 as we translated the coordinate
  50.     // system already
  51.    ctx.fillRect(0, 0, w, h);
  52.    ctx.strokeRect(0, 0, w, h);
  53.  
  54.    // GOOD PRACTICE: a restore for a save!
  55.    ctx.restore();
  56. }
  57. </head>
  58. <body>
  59.      <canvas id=“myCanvas” width=“578” height=“400”>
  60.      </canvas>
  61. </body>
  62. </html>

Drawing text

INTRODUCTION

The canvas API provides two main methods for drawing text: ctx.strokeText(message, x, y) and ctx.fillText(message, x, y).

  1. context.font = “60pt Calibri”;
  2. // .. set color, lineWidth, shadow etc.
  3. // 10, 10 is the start of the baseline, bottom of left leg of the “H” in the
  4. // “Hello World” example.
  5. context.fillText(“Hello World!”, 10, 10);
  6. // Or
  7. context.strokeText(“Hello World!”, 10, 10);

THE CONTEXT.FONT PROPERTY:

The font property is CSS-compliant, and accepts values like:

[font style][font weight][font size][font face]

Accepted values are:

    • font style: normal, italic, oblique, inherit
    • font weight: normal, bold, bolder, lighter, auto, inherit, 100, 200, 300, 400, 500, 600, 700, 800, 900
    • font size: a size in pixels or in points, such as 60pt, 20px, 36px, etc.
    • font face: Arial, Calibri, Times, Courier, etc. Some font faces may not work in all browsers.

Examples:

    • context.font = “60pt Calibri”;
    • context.font = “normal normal 20px Verdana”;
    • context.font = “normal 36px Arial”;
    • context.font = “italic bold 36px Arial”;

THE FILLTEXT() OR STROKETEXT() METHODS

The fillText(message, x, y) or strokeText(message, x, y) methods from the context will actually draw a text message at the origin of the baseline position. In the “Hello World” example, this is located at the bottom of the left leg of the “H”.

There is a fourth optional parameter maxWidth that forces the text to fit into a given width, distorting it if necessary:

  1. context.strokeText(“Hello World!”, x, y [, maxWidth]);
  2. context.fillText(“Hello World!”, x, y [, maxWidth]);

EXAMPLE THAT USES THE MAXWIDTH  PARAMETER OF THE STROKETEXT() OR FILLTEXT() METHODS:

Try it online: http://jsbin.com/zixeve/2/edit

  1. context.font = “60pt Calibri”;
  2. context.lineWidth = 3;
  3. context.strokeStyle = “blue”;
  4. context.fillStyle = “red”;
  5. context.fillText(“Hello World!”, 10, 100);
  6. context.strokeText(“Hello World!”, 10, 100);
  7. // Draw text with constrained width of 250 pixels
  8. context.fillText(“Hello World!”, 10, 160, 250);
  9. context.strokeText(“Hello World!”, 10, 160, 250);
  10. // Constrain width to 150 pixels
  11. context.fillText(“Hello World!”, 10, 220, 150);
  12. context.strokeText(“Hello World!”, 10, 220, 150);

MEASURING THE WIDTH OF A GIVEN TEXT (BOUNDING BOX)

The ctx.measureText() method can be used to get the current width in pixels of a given text, taking into account the diverse properties involved such as font, size, shadow, lineWidth, etc.

Source code extract from this example:

  1. context.font = “60pt Calibri”;
  2. context.lineWidth = 3;
  3. context.strokeStyle = “blue”;
  4. context.fillStyle = “red”;
  5. context.fillText(“Hello World!”, 10, 100);
  6. context.strokeText(“Hello World!”, 10, 100);
  7. var textMetrics = context.measureText(“Hello World!”);
  8. var width = textMetrics.width;
  9. // Draw a text that displays the width of the previous drawn text
  10. context.font = “20pt Arial”;
  11. context.fillText(“Width of previous text: “ + width + “pixels”, 10, 150);
  12. // Draw the baseline of the given width
  13. context.moveTo(10, 100);
  14. context.lineTo(width+10, 100);
  15. context.stroke();

THE CTX.TEXTBASELINE PROPERTY: CHANGE THE WAY THE TEXT IS HORIZONTALLY DRAWN

Try this example at JS Bin

The text baseline is important as it tells how the y parameter of the fillText(“some text”, x, y) and strokeText(“some text”, x, y) methods is interpreted.

Possible values:

Possible values for the textBaseline property
top The text is aligned based on the top of the tallest glyph in the text.
hanging The text is aligned based on the line the text seems to hang from. This is almost identical to top, and in many cases, you cannot see the difference.
middle The text is aligned according to the middle of the text.
alphabetic The bottom of vertically oriented glyphs, e.g. western alphabet like the latin.
ideographic The bottom of horizontally oriented glyphs.
bottom The text is aligned based on the bottom of the glyph in the text, that extends furthest down in the text.

Typical use (taken from the example above):

  1. context.textBaseline = “top”;
  2. context.fillText(“top”, 0, 75);
  3. context.textBaseline = “hanging”;
  4. context.fillText(“hanging”, 40, 75);
  5. context.textBaseline = “middle”;
  6. context.fillText(“middle”, 120, 75);

HORIZONTAL TEXT ALIGNMENT

Try this example online: http://jsbin.com/acudif/3/edit

The textAlign property of the context tells how the x parameter will be used when calling strokeText(“some text”, x, y) and fillText(“some text”, x, y). For example, with textAlign=”center”, the x parameter gives the position of the vertical center of the text, while in textAlign=”right”, x corresponds to the rightmost position of the text.

Typical use (source code taken from the above example):

  1. context.textAlign = “center”;
  2. context.fillText(“center”, 250, 20);
  3. context.textAlign = “start”;
  4. context.fillText(“start”, 250, 40);
  5. context.textAlign = “end”;
  6. context.fillText(“end”, 250, 60);
  7. context.textAlign = “left”;
  8. context.fillText(“left”, 250, 80);
  9. context.textAlign = “right”;
  10. context.fillText(“right”, 250, 100);

Saving and restoring the context

Best practice: save the context at the beginning of any function
that changes the context, restore it at the end of the function!

  1. function drawMonster(x, y, angle, headColor, eyeColor) {
  2.     // BEST PRACTICE : SAVE CONTEXT AND RESTORE IT AT THE END
  3.     ctx.save();
  4.     // Moves the coordinate system so that the monster is drawn
  5.     // at position (x, y)
  6.     ctx.translate(x, y);
  7.     ctx.rotate(angle);
  8.     // head
  9.     ctx.fillStyle=headColor;
  10.     ctx.fillRect(0,0,200,200);
  11.     // eyes
  12.     ctx.fillStyle=‘red’;
  13.     ctx.fillRect(35,30,20,20);
  14.     ctx.fillRect(140,30,20,20);
  15.     // interior of eye
  16.     ctx.fillStyle=eyeColor;
  17.     ctx.fillRect(43,37,10,10);
  18.     ctx.fillRect(143,37,10,10);
  19.  
  20.     
  21.     // BEST PRACTICE!
  22.     ctx.restore();
  23. }

Changing the coordinate system

2D transformations: changing the coordinate system

INTRODUCTION

In this part of the course, we introduce the basics of 2D transformations, a powerful tool that will make things easier as soon as you have to:

    • Draw complex shapes at given positions, with given orientations and sizes,
    • Draw shapes relative to one another.

Let’s start with some simple examples before looking at how we use 2D transforms.

LET’S DRAW THREE RECTANGLES!

If we draw three rectangles of size 100×200 in a 400×400 canvas, one at (0, 0) and another at (150, 0), and a third at (300, 0), here is the result and the corresponding code:

3 green rectangles

JavaScript code extract (see the online example at JS Bin for the complete running code)

  1. function drawSomething() {
  2.      ctx.fillStyle=‘lightgreen’;
  3.  
  4.      ctx.fillRect(0,0,100,200);
  5.      ctx.fillRect(150,0,100,200);
  6.      ctx.fillRect(300,0,100,200);
  7. }

LET’S MODIFY THE CODE SO THAT WE CAN DRAW THESE RECTANGLES AT ANY X AND Y POSITION

What if we wanted to draw these 3 rectangles at another position, as a group? We would like to draw all of them a little closer to the bottom, for example… Let’s add some parameters to the function:  the X and Y position of the rectangles.

The full JavaScript code is (see online running example):

  1. var canvas, ctx;
  2. function init() {
  3.     // This function is called after the page is loaded
  4.     // 1 – Get the canvas
  5.     canvas = document.getElementById(‘myCanvas’);
  6.     // 2 – Get the context
  7.     ctx=canvas.getContext(‘2d’);
  8.     // 3 – we can draw
  9.     drawSomething(0, 100);
  10. }
  11. function drawSomething(x, y) {
  12.     // draw 3 rectangles
  13.     ctx.fillStyle=‘lightgreen’;
  14.     ctx.fillRect(x,y,100,200);
  15.     ctx.fillRect(x+150,y,100,200);
  16.     ctx.fillRect(x+300,y,100,200);
  17. }

At line 10, we called the drawSomething(…) function with 0 and 100 as parameters, meaning “please add an offset of 0 in X and 100 in Y directions to what is drawn by the function…

If you look at the code of the modified function, you will see that each call to fillRect(…) uses the x and y parameters instead of hard coded values. In this way, if we call it with parameters (0, 100), then all rectangles will be drawn 100 pixels to the bottom (offset in y). Here is the result:

rectangles are drawn 100 pixels towards the bottom

OK, NOW LET’S DRAW A SMALL MONSTER’S HEAD WITH RECTANGLES

Now we can start having some fun… let’s draw a monster’s head using only rectangles (online version):

monster made of rectangles

An extract of the JavaScript source code is:

  1. function drawMonster(x, y) {
  2.    // head
  3.    ctx.fillStyle=‘lightgreen’;
  4.    ctx.fillRect(x,y,200,200);
  5.    // eyes
  6.    ctx.fillStyle=‘red’;
  7.    ctx.fillRect(x+35,y+30,20,20);
  8.    ctx.fillRect(x+140,y+30,20,20);
  9.    // interior of eye
  10.    ctx.fillStyle=‘yellow’;
  11.    ctx.fillRect(x+43,y+37,10,10);
  12.    ctx.fillRect(x+143,y+37,10,10);
  13.    // Nose
  14.    ctx.fillStyle=‘black’;
  15.    ctx.fillRect(x+90,y+70,20,80);
  16.    // Mouth
  17.    ctx.fillStyle=‘purple’;
  18.    ctx.fillRect(x+60,y+165,80,20);
  19. }

As you can see, the code uses the same technique, becomes less and less readable. The Xs and Ys at the beginning of each call makes understanding the code harder, etc.

However, there is a way to simplify this => 2D geometric transformations!

GEOMETRIC TRANSFORMATIONS: CHANGING THE COORDINATE SYSTEM

The idea behind 2D transformations is that instead of modifying all the coordinates passed as parameters to each call to drawing methods like fillRect(…), we will keep all the drawing code “as is”. For example, if the monster of our previous example was drawn at (0, 0), we could just translate (or rotate, or scale) the original coordinate system.

Let’s take a piece of code that draws something corresponding to the original coordinate system, located at the top left corner of the canvas:

  1. function drawMonster(x, y) {
  2.    // head
  3.    ctx.fillStyle=‘lightgreen’;
  4.    ctx.fillRect(0,0,200,200);
  5.    // eyes
  6.    ctx.fillStyle=‘red’;
  7.    ctx.fillRect(35,30,20,20);
  8.    ctx.fillRect(140,30,20,20);
  9.    // interior of eye
  10.    ctx.fillStyle=‘yellow’;
  11.    ctx.fillRect(43,37,10,10);
  12.    ctx.fillRect(143,37,10,10);
  13.    // Nose
  14.    ctx.fillStyle=‘black’;
  15.    ctx.fillRect(90,70,20,80);
  16.    // Mouth
  17.    ctx.fillStyle=‘purple’;
  18.    ctx.fillRect(60,165,80,20);
  19.    // coordinate system at (0, 0)
  20.    drawArrow(ctx, 0, 0, 100, 0, 10, ‘red’);
  21.    drawArrow(ctx, 0, 0, 0, 100, 10, ‘red’);
  22. }

This code is the just the same as in the previous example except that we removed all Xs and Yx in the code. We also added at the end (lines 25-26) two lines of code that draw the coordinate system. The drawArrow(startX, startY, endX, endY, width, color) function is a utility function that we will present later. You can see it in the source code of the complete online example on JS Bin: look in the JavaScript tab.

Note that the X and Y parameters are useless for now…

Result:

monster at 0, 0, coordinate system is drawn too as two arrows

Translation using ctx.translate(offsetX, offsetY)

Now, instead of simply calling drawMonster(0, 0), we will call first ctx.translate(100, 100), and look at the result (online code: http://jsbin.com/yuhamu/2/edit)

translated monster

JavaScript code extract:

  1. ctx.translate(100, 100);
  2. drawMonster(0, 0);

Line 1 changes the position of the coordinate system, line 2 draws a monster in the new translated coordinate system. All subsequent calls to drawing methods will be affected and will work in this new system too.

OTHER TRANSFORMATIONS: ROTATE, SCALE

There are other transformations available:

  • ctx.rotate(angle), with angle in radians. Note that the order of transformations is important: usually we translate, then rotate, then scale… If you change this order, you need to know what you are doing…
  • ctx.scale (sx, sy), where scale(1, 1) corresponds to “no zoom”, scale(2, 2) corresponds to “zooming 2x” and scale(0.5, 0.5) corresponds to zooming out to see the drawings half as big as before. If you do not use the same values for sx and sy, you do “asymmetric scaling”, you can distort a shape horizontally or vertically. Try changing the values in the source code of the next online examples.

Here is the previous example, but this time we translated the coordinate system, then rotated it with an angle equal to PI/4 , then we scaled it so that units are half as big (see the example online):

coordinate system translated, rotated and scaled

And here is the code of the transformations we used, followed by the call to the function that draws the monster:

  1. ctx.translate(100, 100);
  2. ctx.rotate(Math.PI/4);
  3. ctx.scale(0.5, 0.5);
  4.  
  5. drawMonster(0, 0);

Line 1 does:

translate coordinate system

Line 2 does:

rotate coordinate system

Line 3 does:

scale coordinate system

Line 4 draws the monster in this new translated, rotated, scaled coordinate system:

coordinate system translated, rotated and scaled

BEWARE: ALL DRAWINGS TO COME WILL BE IN THAT MODIFIED COORDINATE SYSTEM!

If we draw two shapes at two different positions, they will be relative to this new coordinate system.

For example, this code (online at http://jsbin.com/yuhamu/4/edit):

  1. ctx.translate(100, 100);
  2. ctx.rotate(Math.PI/4);
  3. ctx.scale(0.5, 0.5);
  4. // Draw the monster at (0, 0)
  5. drawMonster(0, 0);
  6. // Draw a filled rectagle at (250, 0)
  7. ctx.fillRect(250, 0, 100, 100);

… gives this result:

monster and rectangle in the same coordinate system

HOW CAN WE RESET THE COORDINATE SYSTEM, HOW CAN WE GO BACK TO THE PREVIOUS ONE?

Aha, this is a very interesting question… we will give the answer very soon in the section on saving/restoring the context 🙂

Drawing principles

MORE ABOUT THE “CONTEXT” OBJECT

Before we go on, we should take some time to clarify the way we draw on HTML5 canvases. We already mentioned that we use a graphic context for all the main operations. Whenever a shape, a text, or an image is drawn, the current values of the different properties of the graphic context are taken into account. Some are relevant only for certain kinds of shapes or drawing modes, but you must be aware that it is always the current values of these drawing properties that are used.

Later on we’ll see that there are ways to save and restore this whole set of values, but for now, let’s examine in greater detail some of the properties and methods we’ve already encountered, and introduce new ones.

MORE ABOUT PROPERTIES AND METHODS OF THE CONTEXT OBJECT

fillStyle is a property of the context, similar in a way to a CSS property.

Its value can be one of the following:

    • a color,
    • a pattern (texture), or
    • a gradient.

The default value is the color black. Any kind of drawing in “fill mode” will use the value of this property to determine how to render the “filled part” of the drawing: any filled rectangle will be filled black by default, any filled circle will be filled in black, and so on.

As long as we don’t modify the value of this property, all drawing commands for filled shapes will use the current value.

fillStyle and the other context properties can be considered to be “global variables” of the context.

fillRect(x, y, width, height):  a call to this method draws a filled rectangle.

The two first parameters are the coordinates of the top left corner of the rectangle. This method uses the current value of the fillStyle property to determine how to fill the rectangle.

  1. ctx.fillStyle=‘pink’;
  2. ctx.fillRect(10,10,200,200);

Produces this result:

filled rectangle

strokeStyle is a property of the context similar to fillStyle, but this time for indicating how the shape’s outline should be rendered.

The possible values are the same as those for the fillStyle property: a color, a pattern, or a gradient. This property will be taken into account when wireframe shapes are drawn.

strokeRect(x, y, width, height): like fillRect(…), but instead of drawing a filled rectangle the rectangle is drawn in wireframe mode.

  1. ctx.strokeStyle=‘blue’;
  2. ctx.strokeRect(10,10,200,200);

…produces this result:

stroked rectangle

Only the outline of the rectangle will be drawn, and it will be drawn using the value of the strokeStyleproperty.

clearRect(x, y, width, height): a call to this method erases the specified rectangle.

Actually it draws it in a color called “transparent black” (!) that corresponds to the initial state of the rectangle as if no drawing had occurred.

  1. ctx.fillStyle=‘pink’;
  2. ctx.fillRect(10,10,200,200);
  3. ctx.clearRect(50, 50, 20, 20);

The result is:

clear rect

LET’S SEE SOME SIMPLE EXAMPLES…

Draw a wireframe red rectangle, width lineWidth = 3 pixels.

Interactive example available here at JS Bin

wireframe red rectangle with line width = 3 pixels

Extract from the source code (the part that draws the rectangle):

  1. function drawSomething() {
  2.      // draw a red rectangle, line width=3 pixels
  3.      ctx.lineWidth=3;
  4.      ctx.strokeStyle=‘red’;
  5.      ctx.strokeRect(10,10,80,100);
  6. }

Here, we used “stroke” instead of “fill” in the property and method names (lines 4 and 5): strokeStyle instead of fillStyle, strokeRect(…) instead of fillRect(…).

We also introduced a new property of the context, that applies only when drawing in “stroke” mode, the lineWidth property (line 3), that is used for setting the width of the shape outline. The value is in pixels.

DRAW 2 FILLED RED RECTANGLES WITH A BLUE OUTLINE OF 5 PIXELS AND SOME TEXT

Let’s continue with another example. This time we will draw several shapes that share the same colors – they will be filled in red, with a blue outline. We also show how to draw a text message with a given font.

Online example on JS Bin

rectangles and text that shares colors

Source code extract:

  1. function drawSomething() {
  2.      // set the global context values
  3.     ctx.lineWidth=5;
  4.     ctx.fillStyle=‘red’;
  5.     ctx.strokeStyle=‘blue’
  6.     // font for all text drawing
  7.     ctx.font = ‘italic 20pt Calibri’;
  8.     // Draw the two filled red rectangles
  9.     ctx.fillRect(10, 30, 70, 150);
  10.     ctx.fillRect(110, 30, 70, 150);
  11.     // Draw the two blue wireframe rectangles
  12.     ctx.strokeRect(10, 30, 70, 150);
  13.     ctx.strokeRect(110, 30, 70, 150);
  14.     // Draw a message above the rectangles
  15.     ctx.fillText(“hello”, 70, 22);
  16. }

SUMMARY OF WHAT WE LEARNED

  • “stroke” means “wireframe” or “outlined”, it is a prefix for setting properties or calling methods that will affect wireframe shapes, “fill” is a prefix for filled shapes.
  • To set the properties of wireframe shapes use ctx.strokeStyle= …, for filled shapes use ctx.fillStyle=… So far the values we have used are colors, expressed as strings. Example: ctx.strokeStyle  = ‘blue’;
  • To draw a wireframe rectangle use ctx.strokeRect(x, y, width, height), to draw a filled rectangle use ctx.fillRect(x, y, width, height);
  • To set the line width of wireframe shapes, use the ctx.lineWidth property. Example ctx.lineWidth = 10; ctx.strokeRect(0, 0, 100, 100);  will draw a 100×100 rectangle in wireframe mode, with an outline width of 10 pixels.
  • To draw a text message use ctx.strokeText(message, x, y) or ctx.fillText(message, x, y), for wireframe text or filled text respectively.
  • To set the character font use the ctx.font property; the value is a font in CSS syntax, for example:  ctx.font = ‘italic 20pt Calibri’;

The canvas coordinate system

X AXIS IS HORIZONTAL, DIRECTED TO THE RIGHT
Y AXIS IS VERTICAL, DIRECTED DOWNWARDS

The coordinate system used for drawing in canvases is similar to the one used by many drawing APIs like Java2D: the (0 , 0) is in the top left corner while the X axis is going to the right and the Y axis to the bottom, as  shown in the following picture (author Mark Pilgrim):

coordinate system

 

Typical use of the <canvas> element

1 – Add the <canvas> element into an HTML page

  1. <canvas id=“myCanvas” width=“300” height=“225”>
  2.     Fallback content that will be displayed in case the web browser
  3.     does not support the canvas tag or in case scripting
  4.     is disabled.
  5. </canvas>

Place code similar to the above somewhere in an HTML page. This example defines an area of 300 by 225 pixels on which content can be rendered with JavaScript.

Normally you should see nothing as a result; by default canvases are “transparent”.

Make it visible using CSS:

CSS code:

  1. <style>
  2.     #myCanvas {
  3.         border:1px solid black;
  4.     }
  5. </style>

2 – Select the <canvas> element for use from JavaScript

We can have more than one <canvas> in a single page, and canvases will be manipulated with JavaScript like other elements in the DOM.

For example with:

  1. var canvas = document.getElementById(“myCanvas”);

… or with the querySelector() method introduced by HTML5, that use the CSS selector syntax for selecting elements:

  1. var canvas = document.querySelector(“#myCanvas”);

3 – get a “2D context” associated with the canvas, useful for drawing and setting drawing properties (color, etc.)

Once we have a pointer to the <canvas>, we can get a “context”.

This particular object is the core of the canvas JavaScript API.

It provides methods for drawing, like fillRect(x, y, width, height) for example, that draws a filled rectangle, and properties for setting the color, shadows, gradients, etc.

Getting the context (do this only once):

  1. var ctx=canvas.getContext(‘2d’);

Set the color for drawing filled shapes:

  1. ctx.fillStyle=‘red’;

Draw a filled rectangle:

  1. ctx.fillRect(0,0,80,100);

COMPLETE EXAMPLE THAT DRAWS A FILLED RECTANGLE IN RED

Try it online at JS Bin

Result:

red rectangle draw in a canvas

Source code:

  1. <!DOCTYPE html>
  2. <html lang=”en”>
  3. <head>
  4.  <style>
  5.      #myCanvas {
  6.          border: 1px solid black;
  7.      }
  8.  </style>
  9.    var canvas, ctx;
  10.  
  11.    function init() {
  12.      // This function is called after the page is loaded
  13.      // 1 – Get the canvas
  14.      canvas = document.getElementById(‘myCanvas’);
  15.      // 2 – Get the context
  16.      ctx=canvas.getContext(‘2d’);
  17.      // 3 – we can draw
  18.      drawSomething();
  19.    }
  20.    function drawSomething() {
  21.      // draw a red rectangle
  22.      ctx.fillStyle=‘#FF0000’;
  23.      ctx.fillRect(0,0,80,100);
  24.    }
  25. </head>
  26. <body onload=init();>
  27.     <canvas id=“myCanvas” width=“200” height=“200”>
  28.             Your browser does not support the canvas tag.
  29.     </canvas>
  30. </body>
  31. </html>

Explanation

Only access elements when the DOM is ready:

Notice that we wrote an “init” function (line 12) that is called only when the page has been entirely loaded (we say “when the DOM is ready”). There are several ways to do this. In this example we used the <body onload=”init();”> method, at line 32.

It’s good practice to have such a function, as we cannot access the elements of the page before the page has been loaded entirely and before the DOM is ready.

Another way is to put the JavaScript code at the end of the document (between …), right before the </body>. In this case when the JavaScript code is executed, the DOM has already been constructed.

Start by getting the canvas and the context:

Before drawing or doing anything interesting with the canvas, we must first get its drawing “context”. The drawing context defines the drawing methods and properties we can use.

Good practice is to get the canvas, the context, the width and height of the canvas and other global objects in this “init” function.

After the context is set, we can draw, but first let’s set the current color for filled shapes:

The example shows the use of the fillStyle property at line 27 – useful for specifying the way shapes will be filled. In our case this line indicates the color of all the filled shapes we are going to draw:

  1. ctx.fillStyle=‘#FF0000’;

The context property named fillStyle is used here. This property can be set with a color, a gradient, or a pattern. We will see examples of these later on in the course.

When we set it with a color, we use the CSS3 syntax.

The example says that all filled shapes will use the color “#FF0000”, which corresponds to a pure red color using the CSS RGB hexadecimal encoding (we could also have used ctx.fillStyle=’red’);

Then we can draw:

  1. ctx.fillRect(0,0,80,100);

This line is a call to the method fillRect(top left X coordinate, top left Y coordinate, width, height), which draws a filled rectangle.

The way the rectangle will be filled depends on the current value of several properties of the context, in particular the value of the fillStyle property. So, in our case, the rectangle will be red.

SUMMARY OF THE DIFFERENT STEPS

    1. Declare the canvas, remembering to add an id attribute, and fallback content:
      <canvas id=”myCanvas” width=”200″ height=”200″>
      …fallback content…
      </canvas>
    2.  Get a reference to the canvas in a JavaScript variable using the DOM API:
      var canvas=document.getElementById(‘myCanvas’);
    3. Get the context for drawing in that canvas:
      var ctx=canvas.getContext(‘2d’);
    4. Specify some drawing properties (optional):
      ctx.fillStyle=’#FF0000′;
    5. Draw some shapes:
      ctx.fillRect(0,0,80,100);

Canvas cheatsheet

Canvas cheatsheet with all API methods and properties

This is a valuable resource, which we recommend either printing or keeping open in a separate browser tab. The original version was located at “http://blog.nihilogic.dk/2009/02/html5-canvas-cheat-sheet.html&#8221;, but this URL no longer works. Here, we share the mirrored versions (HTML and PDF ones).

HTML VERSION

PDF VERSION

The image links to a PDF – just click on it.

https://d37djvu3ytnwxt.cloudfront.net/assets/courseware/v1/59510028561daf62e00bf9f6f066b033/asset-v1:W3Cx+HTML5.1x+3T2016+type@asset+block/HTML5_Canvas_Cheat_Sheet.pdf

canvas sheet API

Intro to the canvas element

Draw and animate graphics: the <canvas> element

The W3C HTML5 specification about the <canvas> element states that “The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, or other visual images on the fly.

The canvas has been designed for pixel-based graphics, while SVG (Scalable Vector Graphics, another W3C standard) is for vector-based graphics.

The canvas is also used to do animations at 60 frames per second (useful for games), to display videos with special effects, to display a webcam stream, and so on.

Performance is generally good today, since most Web browsers support hardware acceleration or will add support soon. Back in 2009, this demo ran at only a few images per second on some low-end computers (smartphones that could run HTML5 demos, such as this one, did not exist at that time ) due to the lack of hardware acceleration support in the browser’s implementations of the canvas API.

Note: 3D drawing using the WebGL API is also possible in a <canvas>, but will not be covered in this course. For the most curious among you, please have a look at the two popular libraries for doing 3D drawing/animation in a <canvas>: BabylonJS and ThreeJS.

An up-to-date version of this table is at: http://caniuse.com/#feat=canvas

GOOD EXTERNAL RESOURCES

 

About JavaScript and HTML5

EXTERNAL RESOURCES

  • The book I used to learn JavaScript myself: Object Oriented JavaScript by Stoyan Stefanov
  • Mozilla Developper Network has a JS guide too.

WHAT DO YOU NEED? HOW TO DEBUG? HOW TO CATCH ERRORS?

First of all, you need to find a way to debug your code and see errors. If your work does not produce any results, you must know why!

For that you will use the dev. tools of your browser. Press F12 in Windows or cmd-alt-i in Mac to open the dev. tools, then go to the console tab: this is where errors will be displayed, or messages of your own (use the console.log(string) JavaScript function in the JavaScript code embedded in your html page). In the console, you will be able to type any JavaScript command.

Let’s look at  this example on JS Bin:

<!DOCTYPE html>
<html>
  <head>
  <meta charset=utf-8 />
  <title>Web Audio API</title>
  <script>
   console.log("Some JavaScript code has been executed");
  </script>
  </head>
  <body>
    <h1>JavaScript debugging using the dev tool console</h1>
  </body>
</html>

The simplest way to add JavaScript code in an HTML page, is by using the ... element.

The code in this example is executed sequentially when the page is loaded: JavaScript code is executed before the browser could see the rest of the page (as the is located before the <body>).

The only line of code we have is console.log(“Some JavaScript code has been executed”);

Ok, now, let’s make an error: change console.log() into consollle.log(). Let’s see what happens:

view of the javascript console

And if we run it standalone and use the dev. tool console:

View of the JavaScript console

And if we click on the line number in the right, the dev. tool shows the source code centered on the line that caused the error:

View of the JavaScript console

Without such tools, debugging JavaScript code is impossible. So you need to look at some basic tutorials on how to use the dev. tools of your browsers, since they differ from one another in the way they work – although the principles remain the same.

ABOUT THE ASYNCHRONOUS NATURE OF JAVASCRIPT

Some of you may not be used to “asynchronous programming”, “callbacks” etc. We recommend to read this article on WikiPedia and this thread on StackOverflow.