Friday, April 8, 2016

Drawing rectangles - immediate drawing mode

NTRODUCTION

In the previous sections, we learned how to draw filled or wireframe rectangles.
As soon as the ctx.strokeRect(x, y, width, height) or the ctx.fillRect(x, y, width, height) method is called, a rectangle is indeed drawn immediately in the canvas. 
While drawing rectangles with strokeRect or fillRect, drawing text or drawing images, all these shapes will be drawn in immediate mode.
Another mode called "path mode" or "buffered mode" will be seen later in this course, which will be useful for drawing lines, curves, arcs, and also rectangles. Rectangles are the only shapes that have methods for drawing them immediately and also other methods for drawing them in "path/buffered mode".

EXAMPLE THAT DRAWS RECTANGLES IN IMMEDIATE MODE AND ALSO SHOWS GOOD PRACTICE

We'll just give an example here that draws several rectangles, filled or wireframe, with different colors and line widths.
rectangles drawn at different positions
Source code:
  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. <script>
  11.     var canvas, ctx;
  12.  
  13.     window.onload = function () {
  14.        canvas = document.getElementById('myCanvas');
  15.        ctx = canvas.getContext('2d');
  16.  
  17.        // black rectangle, default color (black)
  18.        ctx.fillRect(10, 10, 100, 100);
  19.        // outlined rectangle, default color
  20.        ctx.strokeRect(150, 10, 100, 100);
  21.  
  22.        // outlined rectangle filled in red, outline blue
  23.        ctx.fillStyle = 'red';
  24.        ctx.strokeStyle = 'lightBlue';
  25.        ctx.lineWidth = 10;
  26.        ctx.fillRect(100, 150, 150, 150);
  27.        ctx.strokeRect(100, 150, 150, 150);
  28.  
  29.        // A function that automatizes previous drawing
  30.        var angle = Math.PI / 10;
  31.        drawFilledRectangle(300, 150, 150, 150, 'pink', 'green', 10, angle);
  32.        drawFilledRectangle(300, 150, 150, 150, 'yellow', 'purple', 10, angle +0.5);
  33. };
  34.  
  35. function drawFilledRectangle(x, y, w, h, fillColor, strokeColor, lw, angle) {
  36.     // GOOD PRACTICE : save if the function change the context
  37.     // or coordinate
  38.     // system
  39.     ctx.save();
  40.  
  41.     // position coordinate system
  42.     ctx.translate(x, y);
  43.     ctx.rotate(angle);
  44.  
  45.     // set colors, line width...
  46.     ctx.lineWidth = lw;
  47.     ctx.fillStyle = fillColor;
  48.     ctx.strokeStyle = strokeColor;
  49.  
  50.     // draw at 0, 0 as we translated the coordinate
  51.     // system already
  52.    ctx.fillRect(0, 0, w, h);
  53.    ctx.strokeRect(0, 0, w, h);
  54.  
  55.    // GOOD PRACTICE : a restore for a save!
  56.    ctx.restore();
  57. }
  58. </script>
  59. </head>
  60. <body>
  61.      <canvas id="myCanvas" width="578" height="400">
  62.      </canvas>
  63. </body>
  64. </html>

Drawing text

INTRODUCTION

The canvas API provides two main methods for drawing text: ctx.strokeText(message, x, y) andctx.fillText(message, x, y).
It also provides a set of context properties for setting the character font and style, for laying out the text, etc.

TYPICAL USE

Try this example online: http://jsbin.com/cutoja/2/edit
example of text drawn in a canvas
Source code extract:
  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);

Look at the code from the example provided: http://jsbin.com/cutoja/2/edit - change the position where the text is drawn, change font attributes, etc.

THE CONTEXT.FONT PROPERTY:

It is possible to draw text in a canvas using the font property of the context to specify the font style (plain, bold, italic), the size, and the font name. Other properties such as strokeStyle or fillStyle, as well as other properties detailed in the next subchapters, will also be taken into account.
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 the 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() ORFILLTEXT() METHODS:

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

MEASURING THE WIDTH OF A GIVEN TEXT (BOUNDING BOX)

Try this example online: http://jsbin.com/texigo/1/edit
measure text width
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

text baseline
The text baseline is important as it tells how the y parameter of the fillText("some text", x, y) andstrokeText("some text", x, y) methods is interpreted.
The textBaseline property of the context is used to specify the different ways one can position the baseline of a given text. The example above shows the different possible values for this property and the corresponding results. The default value is "alphabetic" and corresponds to what has been used in the previous "Hello World" example.
Possible values:
Possible values for the textBaseline property
topThe text is aligned based on the top of the tallest glyph in the text.
hangingThe 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.
middleThe text is aligned according to the middle of the text.
alphabeticThe bottom of vertically oriented glyphs, e.g. western alphabet like the latin.
ideographicThe bottom of horizontally oriented glyphs.
bottomThe 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
horizontal text alignment
The textAlign property of the context tells how the x parameter will be used when callingstrokeText("some text", x, y) and fillText("some text", x, y). For example, withtextAlign="center", the x parameter gives the position of the vertical center of the text, while intextAlign="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";
  1. context.fillText("start", 250, 40);
  2. context.textAlign = "end";
  3. context.fillText("end", 250, 60);
  4. context.textAlign = "left";
  5. context.fillText("left", 250, 80);
  6. context.textAlign = "right";
  7. context.fillText("right", 250, 100);

Drawing images

INTRODUCTION

Load images in the background, wait for them to be loaded before drawing!

Working with images is rather simple, except that we need the images to be fully loaded into memory before drawing them. Loading images is an asynchronous process we need to take care of. Working with multiple images might also be difficult for beginners. Later on in this course, we will present a multiple image loader.
It is also possible to draw images from a video stream, images corresponding to another canvas content, or images that are defined by <img> HTML elements in the page. We will see that as well in the following parts of this chapter.
But let's start with a basic example!

EXAMPLE 1: DRAWING AN IMAGE

Try this example online: http://jsbin.com/wifeka/1/edit
html5 logo
Source code:
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4.   <script>
  5.       window.onload = function() {
  6.         // Necessity to run this code only after the web page has been loaded.
  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";
  21.      };
  22.    </script>
  23. </head>
  24. <body>
  25.     <canvas id="myCanvas" width="512" height="512"></canvas>
  26. </body>
  27. </html>

Several things need to be explained here:

    1. We have to create a JavaScript Image object (line 10),
    2. When we set the src attribute of this object with the URL of the image file, then an asynchronous  request is sent in the background by the browser. Loading a big image may take some time, so the rest of the JavaScript code continues running. This is why we call it "asynchronous".
    3. When the image file has been loaded, the browser calls the onload callback associated with the image(line 14). 
    4. We draw the image only from inside this callback, otherwise we have no guarantee that the image has been loaded and can be usable. The actual drawing here is done line 17.

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.
See picture below :
drawing images with subimages

EXAMPLE 2: SHOW THE DIFFERENT VARIANTS OF DRAWIMAGE(...)

variants of drawImages, with the HTML5 logo drawn at different sizes, or with just a sub part of it
Source code extract:
  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 = 100x100 pixels
  9.    context.drawImage(imageObj, 0, 10, 100, 100);
  10.    // with size = 150x150
  11.    context.drawImage(imageObj, 80, 10, 150, 150);
  12.    // with size = 200x200
  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";
  20. };

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

Sometimes, you may want to draw an image that is already declared in the HTML document as an <img src="..."> element. Remember that when you add an <img> in the document, the browser starts downloading it in background. 
WRONG => indeed, you could try drawing it using some code like this:
  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">
  6. <script>
  7.      canvas = document.getElementById("myCanvas");
  8.      var ctx = canvas.getContext("2d");
  9.      var logo = document.querySelector("#logo");
  10.      ctx.drawImage(logo, 0, 0, 100, 100);
  11. </script>
  12. </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!
If you try to draw an image that is not loaded or partially loaded, you will have unexpected results!
Best practice: only draw an image that is fully loaded, use 
the 
onload callback!
GOOD => the right way to do that 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. <script>
  5.    var canvas, context;
  6.    window.onload = function() {
  7.       canvas = document.getElementById("myCanvas");
  8.       context = canvas.getContext("2d");
  9.  
  10.       draw();
  11.    };
  12.    function draw() {
  13.       var imageObj = document.querySelector("#logo");
  14.       console.log("image is already loaded, we draw it!");
  15.       context.drawImage(imageObj, 0, 10, 100, 100);
  16.    }
  17. </script>
  18. </head>
  19. <body>
  20. <canvas id="myCanvas" width="512" height="512"></canvas>
  21. </p>
  22. <img id="logo" src="http://www.w3.org/html/logo/downloads/HTML5_Logo_512.png">
  23. </body>
  24. </html>
With large image files, this will not break nor produce unexpected results: http://jsbin.com/mayoma/5/edit.
The load event occurs when the DOM implementation finishes loading all content within a document, all frames within a FRAMESET, or an OBJECT element.
Results with a very large image (5160x3270 pixels):
same example with a large image

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. This can be done at video frequency on most modern computers or mobile devices.
Online example at http://jsbin.com/dajena/3/edit
This example shows:
    • <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. 
video wall with on top a video element playing a streames video file, and at bottom a canvas with the current video image drawn 4 times, including a rotating one
Source code extract:
  1. <script>
  2.    var video;
  3.    var canvas, ctx;
  4.    var angle = 0;
  5.  
  6. function init() {
  7.    video = document.getElementById('sourcevid');
  8.    canvas = document.getElementById('myCanvas');
  9.    ctx = canvas.getContext('2d');
  10.  
  11.    setInterval("processFrame()", 25); // call processFrame each 25ms
  12. }
  13.  
  14. function processFrame() {
  15.     ctx.drawImage(video, 0, 0, 320, 180);
  16.     drawRotatingVideo(480, 90);
  17.     ctx.drawImage(video, 0, 180, 320, 180);
  18.     ctx.drawImage(video, 320, 180, 320, 180);
  19. }
  20.  
  21. function drawRotatingVideo(x, y) {
  22.      // Clear thze zone at the top right quarter of the canvas
  23.     ctx.clearRect(320, 0, 320, 180);
  24.  
  25.     // We are going to change the coordinate system, save the context !
  26.     ctx.save();
  27.     // translate, rotate and recenter the image at its "real" center,
  28.     //not the top left corner
  29.     ctx.translate(x, y);
  30.     ctx.rotate(angle += 0.01); // rotate and increment the current angle
  31.     ctx.translate(-80, -45);
  32.  
  33.     ctx.drawImage(video, 0, 0, 160, 90);
  34.  
  35.     // restore the context
  36.     ctx.restore();
  37. }
  38. </script>
  39. </head>
  40.  
  41. <body onload="init()" >
  42. <p>This is a <video> element: </p>
  43. <video id="sourcevid" autoplay="true" loop="true">
  44. <sourcesrc="http://www.craftymind.com/factory/html5video/BigBuckBunny_640x360.mp4"
  45.          type="video/mp4" />
  46. <sourcesrc="http://www.craftymind.com/factory/html5video/BigBuckBunny_640x360.ogv"
  47.          type="video/ogg"/>
  48. </video>
  49. <p>This is a <canvas> element: </p>
  50. <canvas id="myCanvas" width="620" height="360"></canvas>
  51. </body>
    • Line 11: the call to setInterval will make the browser execute the processFrame function each 25ms.
    • Lines 15, 17 and 18: iprocessFramedrawImage(...) is called 3 times with the video element passed as first parameter.
    • Line 43: the video element declared at line 43 has autoplay=true and loop=true, it starts playing the video as soon as possible and will loop it.
    • Line 21: We implemented a rotating video effect in the drawRotatingVideo. The use of context save/restore is primordial as this function changes the coordinate system at each call, translating and rotating it. Notice the extra translation at line 31 that translates backwards the coordinate system with half of the size of the image that is drawn. We did that in order to make the image rotate around the center of the rectangle, instead of around the top left corner at (0, 0) by default. Try commenting out this line in the running example and you will see what we mean.

9 comments:

  1. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Front end developer learn from Javascript Online Training from India . or learn thru ES6 Training in Chennai. Nowadays JavaScript has tons of job opportunities on various vertical industry. HTML5 CSS3 Javascript Online Training from India

    ReplyDelete
  2. The blog is unique that’s providing the nice material. Please post more interesting articles here.urgent care clinic near me

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me..
    I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging
    aws training in chennai | aws training in annanagar | aws training in omr | aws training in porur | aws training in tambaram | aws training in velachery

    ReplyDelete
  5. I always like and such a super contents of these post. Education is the extreme motivation that open the new doors of data and material. So we need to update ourself day by day. this articles drives me to travel in an informative path. Thanks for this amazing work.

    Aws Training in Chennai

    Aws Training in Velachery

    Aws Training in Tambaram

    Aws Training in Porur

    Aws Training in Omr

    Aws Training in Annanagar

    ReplyDelete
  6. This post is so interactive and informative.keep update more information...
    SEO Training in Tambarama
    SEO Training in Chennai

    ReplyDelete