Coding Canvas

Introduction

Since its inception, HTML was invented with text in mind. While the insertion of images can be done through the <img> tag, the inclusion of animation will require third-party plug-ins. In this respect, traditional HTML is vastly lacking in its capability to meet the multimedia needs of modern web applications. This has since changed with the introduction of HTML Canvas API.

The HTML Canvas API manifests itself in the form of an HTML element called <canvas>. On a web page, this <canvas> element defines a 2-D resolution-dependent bitmap canvas which can be used for rendering and manipulating graphics, texts, images on the fly with the help of some client-side scripting language like JavaScript. In a nutshell, JavaScript is the artist who makes use of the tools (methods and properties) provided by the HTML Canvas API to draw, transform, and animate shapes, texts, images and other multimedia resources on an area of a web page defined by the <canvas> element.

Check out this short video clip at https://youtu.be/G3CnqX43loE called “Bouncing on Canvas” to catch a glimpse of a simple 2-D animation that was created using the HTML Canvas API.

If you are keen to find out how the “Bouncing on Canvas” was created, you have certainly come to the right place. Follow this article and you will be well on your way to creating your own 2-D web animation using the HTML Canvas API.

Preparing the Canvas

Every artist needs a canvas to draw upon. You will create your first HTML  canvas by typing the following code on the upper part of Figure 1 using a text editor, save it with .html extension, and launch it on a browser. What do you see?

Figure1
Figure 1: Where is the Canvas?

Nothing except the heading as shown on the lower part of Figure 1. Where is the canvas? The following <canvas> markup has created a rectangular area of 300 pixels wide by 200 pixels tall with no content and no borders.

<canvas id="mycanvas" width="300" height="200"></canvas>

You can have multiple <canvas> elements on the same page. Each canvas will maintain its own state and be identified by an id attribute. The id attribute will enable JavaScript to access a particular canvas. The id of the canvas in Figure 1 is called “mycanvas“.

Let’s add some inline CSS style to it so that you can verify its existence. Add the CSS code as shown on the upper part of Figure 2, save it, and refresh your browser.

Figure2
Figure 2: Now You See It

Now you should be able to see a rectangular area displayed on the browser as shown on the lower part of Figure 2. That is the canvas!

Notice that in between the <canvas> and </canvas> tags I have added a statement which will be displayed in place of the canvas when the browser does not support <canvas> tag.

That’s it? Wait, you’ve got to be patient, it is just the beginning of the journey. Read on …

Getting Your Feet Wet

In order to get acquainted well with the various methods and properties of HTML canvas, it is important to first have a good understanding of how drawing is being carried out on the canvas generally. I will illustrate this with a simple triangle example.

The Coordinates and the Path

The first step of any drawing on the canvas is to define the path of the shape, triangle in this case. Leave the computer aside, we will work from a piece of paper first.

Assuming the paper is your browser screen, draw a rectangle starting from the top left hand corner of the paper. The width and height of the rectangle are 300 units and 200 units respectively. That is the equivalent of HTML canvas in Figure 2. However, unlike the coordinates that we have learned in geometry, the origin of coordinates (x=0, y=0) of the canvas is located at the top left hand corner. The x-axis runs horizontally from the origin to the right while the y-axis vertically from the orgin downward. This is best illustrated by the Bouncing on Canvas video which shows the changing coordinates of the CodeProject icon as it moves.

We will adopt the canvas coordinates for the paper. Move your index finger to a start point (x=50, y=50) inside the rectangle on the paper. Create a path by moving your finger from the last position which is the start point to a second point (x=150, y=100). Likewise, create another path from the second point to a third point (x=50, y=150). Lastly, close the path by moving your finger back to the start point. What does the path look like? Yes, it is a triangle, short of drawing it out.

The highlighted code (written in JavaScript language) in Figure 3 does just that – define the path of a triangle as you have just done on the paper. Add the highlighted code in Figure 3 to your HTML document. At this stage, you will not see any drawing of the triangle on the browser yet.

Figure3
Figure 3: Defining the Path

I will explain the highlighted code in Figure 3.

  • The JavaScript code is enclosed inside a <script> and a </script> tags. That is one way of inserting JavaScript inside an HTML document.
  • The first line of code finds the target canvas where the drawing is to be done by its id, i.e. “mycanvas“. The target canvas is then assigned to a variable called “canvas“. (var is a JavaScript keyword for declaring a variable.)
    var canvas = document.getElementById("mycanvas");
  • The second line of code calls the canvas’ getContext() method by passing the string “2d” as the sole parameter. The getContext() method will return a 2-dimensional drawing context object which is a built-in HTML object with many properties and methods defined for drawing paths, shapes, text, images, and more. We can liken the context object to a toolbox and the various properties and methods of the context object as the tools inside the toolbox. We will assign this drawing context to a variable called “context“.
    var context = canvas.getContext("2d");
  • The third line of code tells the browser that it is going to define a new path for the context by calling the beginPath() method of the context object.
    context.beginPath();
  • The fourth line of code moves the context to a start point (x=50, y=50) by calling the moveTo() method of the context object, similar to the paper exercise.
    context.moveTo(50,50);
  • The fifth lines of code creates a path from the last point which is the start point to a new point (x=150, y=100) by calling the lineTo() method of the context object, similar to the paper exercise.
    context.lineTo(150,100);
  • The sixth line of code creates a path from the last point (x=150, y=100) to a new point (x=50, y=150) similar to the paper exercise.
    context.lineTo(50,150);
  • The last line of code closes the path by creating a path from the last point (x=50, y=150) back to the start point (x=50, y=50) by calling the closePath() method of the context object, similar to the paper exercise.
    context.closePath();

Drawing It Out

You have just defined a path on the canvas. We will call the strokeStyle property of the context object to assign a color to the stroke. Here it simply sets the stroke color to “red”. Next, we call the stroke() method of the context object to draw out the path. Add the highlighted code on the upper part of Figure 4, save it and view it on a browser. You should be able to see a red-outlined but empty-filled triangle being drawn on your browser screen as shown on the lower part of Figure 4.

Figure4
Figure 4: Drawing the Path

Filling the Drawing

Let’s fill the triangle shape with red color. First, assign the color “red” to the fillStyle property of the context object, then call its fill() method to fill the drawing. Add the highlighted code on the upper part of Figure 5, save it and view it on a browser. You should be able to see a red-color-filled triangle being drawn on your browser screen as shown on the lower part of Figure 5.

Figure5
Figure 5: Filling the Drawing

Congratulations! You have just successfully drawn a red triangle on a web page. It is now your turn to do a little exercise codenamed “Kissing Triangles” where you will add a blue triangle beside the red one. (Figure 6)

Figure6
Figure 6: Kissing Triangles

You will insert your code in the highlighted area as shown in Figure 7. As you are starting a new path, you have to call the beginPath() of the context object first, before creating the code for the new path. However, if you have difficulty accomplishing the “Kissing Triangles” exercise, you may defer it until you have learned enough from this article.

Figure7
Figure 7: Kissing Triangles

Getting Ready to Dive…

Having gotten your feet wet, you are now ready to dive deeper into the canvas affair. Let’s set the stage for the subsequent hands-on session. Create an HTML file with the following code and save it as index.html. As you dive in, you will try out the various code snippets by adding them in between the comment tags of start and end.

<!DOCTYPE HTML>
<html>
<head>
<title>Coding Canvas</title>
</head>
<body>
<br />
<h1>Texts</h1>
<p>
<canvas id="mycanvas" width="350" height="200" style="border:1px solid #000000;">
    Oops! This browser does not support the HTML canvas tag.
</canvas>
<!-- start -->

<!-- end -->
 </body>
</html>

Rectangles

Let’s start by drawing some rectangles on the canvas. There are four methods for drawing rectangles on the canvas – rect(), fillRect(), strokeRect(), clearRect(). Tables 1 describes these methods. Code snippets, and the corresponding outputs are also included in the tables for try out and verification purposes respectively.

Table 1: Rectangle Methods
Method Description / Code Snippets
rect() The rect() method defines a rectangular path on the canvas. The default color is black. It will need to use the fill() or the stroke() method to actually draw the rectangle.The rect() method takes 4 parameters:

  • x coordinate of the start point
  • y coordinate of the start point
  • width of the rectangle
  • height of the rectangle

All coordinates are relative to the origin, i.e the top left corner, of the canvas.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');

context.beginPath();
context.rect(10,10,165,90);
context.stroke();

context.beginPath();
context.rect(175,100,165,90);
context.fill();
</script>

rect1

strokeRect() The strokeRect() method draws a rectangle (no fill) on the canvas. It combines the methods of rect() and stroke().The strokeRect() method takes 4 parameters similar to rect().

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.strokeRect(10,10,165,90);
</script>

rect2

fillRect() The fillRect() method draws a filled rectangle on the canvas. It combines the methods of rect() and fill().The fillRect() method takes 4 parameters similar to rect().

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.fillRect(175,100,165,90);
</script>

rect3

clearRect() The clearRect() method clears all the pixels within a rectangle area.The clearRect() method takes 4 parameters similar to rect().

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.fillRect(175,100,165,90);
context.clearRect(200,120,100,50);
</script>

rect4

Paths, Lines, and Arcs

In the beginning part of the article, you have done your first drawing on the canvas by using some methods to define the path of a triangle and subsequently to draw it out on canvas. We will now take a closer look into these and other methods for defining paths, and drawing lines and arcs.

Table 2: Paths, Lines, and Arcs Methods
Method Description / Code Snippets
moveTo()lineTo()stroke() The moveTo() method takes a x coordinate and a y coordinate as parameters and moves the path to the point specified by these parameters on the canvas.The lineTo() method takes a x coordinate and a y coordinate as parameters and create a path from the last point to a point specified by these parameters on the canvas.The stroke() method draws out the path on the canvas as defined by the moveTo() and lineTo() methods. The stroke() method takes no parameters.

<script>
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.moveTo(50,50);
context.lineTo(300,150);
context.stroke();
</script>

line1

beginPath() The beginPath() method begins a new path or resets the current path. It has no parameters.To define multiple disjoint paths on the same canvas, we have to add a call to beginPath() method before the definition of each new path.

<script>
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");

context.beginPath();
context.moveTo(50,50);
context.lineTo(300,150);
context.stroke();

context.beginPath();
context.moveTo(50,150);
context.lineTo(300,50);
context.stroke();
</script>

line2

closePath() The closePath() method creates a path from the last point to the start point on the canvas, effectively closing and forming the shape of the path. This method is very handy in drawing irregular shape.The closePath() method has no parameters.

<script>
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.moveTo(250,50);
context.lineTo(150,100);
context.lineTo(250,150);
context.closePath();
context.stroke();
</script>

line3

fill() The fill() method will fill the current path with the current fill style. The default fill style is black color.The fill() method has no parameters

<script>
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.moveTo(250,50);
context.lineTo(150,100);
context.lineTo(250,150);
context.closePath();
context.stroke();
context.fill();
</script>

line4

clip() The clip() method is used to clip a region from the original canvas. Once a region is clipped, all subsequent drawings will be confined to the clip region. The clip() method has no parameters.The code below illustrates the effect of clipping on the same rectangle before (red) and after (blue) calling the clip() method.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.rect(50,50,250,100);
context.stroke();
context.fillStyle="red";
context.fillRect(20,20,100,100);
context.clip();
context.fillStyle="blue";
context.fillRect(20,20,100,100);
</script>

clip

arc() The arc() method defines an arc path on the canvas. The default color is black. It will need to call the fill() or the stroke() method to actually draw out the arc path.The arc() method takes 6 parameters:

  • x coordinate of the center of the arc
  • y coordinate of the center of the arc
  • radius of the arc
  • start angle of the arc
  • end angle of the arc
  • an optional boolean to indicate whether the path should be drawn counterclockwise (default as false) or clockwise (true)

The angle of the arc is expressed in terms of radian where one radian is equal to the length of the radius on the circumference. The angle of 0 radian is at 3 o’clock position of a circle. To convert from degrees to radians, just multipy the degree by “Math.PI/180” in JavaScript. For example, 5 degree is equal to the radian of (5 x Math.PI / 180).

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');

context.beginPath();
context.arc(50,100,30,0,0.5*Math.PI);
context.stroke();
context.stroke();

context.beginPath();
context.arc(130,100,30,0,1*Math.PI);
context.stroke();

context.beginPath();
context.arc(210,100,30,0,1.5*Math.PI);
context.stroke();

context.beginPath();
context.arc(290,100,30,0,2*Math.PI);
context.stroke();
</script>

arc1

arcTo() The arcTo() method creates an arc between two tangents on the canvas. It will need to call the fill() or the stroke() method to actually draw out the arc path.The arcTo() method takes 5 parameters:

  • x coordinate of the beginning of the arc
  • y coordinate of the beginning of the arc
  • x coordinate of the end of the arc
  • y coordinate of the end of the arc
  • radius of the arc

The code below will draw a blue arc franked by 2 tangent lines in green colors. The 2 green lines are only here to help in visualization.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');

context.beginPath();
context.moveTo(100,60);  
context.arcTo(200,30,240,160,50); 
context.strokeStyle="blue";
context.stroke();

context.beginPath();
context.moveTo(100,60);  
context.lineTo(200,30); 
context.lineTo(240,160);
context.strokeStyle="green";
context.stroke();
</script>

arcto

quadraticCurveTo() The quadraticCurveTo() method creates a quadratic path guided by a control point. It will need to call the fill() or the stroke() method to actually draw out the arc path.The quadraticCurveTo() method takes 4 parameters:

  • x coordinate of the control point
  • y coordinate of the control point
  • x coordinate of the end point
  • y coordinate of the end point

The code below will draw a blue quadratic arc franked by 2 green lines. The 2 green lines are only here to help in visualizing the start point (80, 40), control point (80, 180), and the end point (300, 20).

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');

context.beginPath();
context.moveTo(80,40);
context.quadraticCurveTo(80,180,300,20);
context.strokeStyle="blue"
context.stroke();

context.beginPath();
context.moveTo(80,40);
context.lineTo(80,180);
context.lineTo(300,20);
context.strokeStyle="green"
context.stroke();
</script>

quadraticCurveTo

bezierCurveTo() The bezierCurveTo() method creates a bezier path guided by 2 control points. It will need to call the fill() or the stroke() method to actually draw out the arc path.The bezierCurveTo() method takes 6 parameters:

  • x coordinate of the first control point
  • y coordinate of the first control point
  • x coordinate of the second control point
  • y coordinate of the second control point
  • x coordinate of the end point
  • y coordinate of the end point

The code below will draw a blue bezier arc franked by 2 green lines. The 2 green lines are only here to help in visualizing the start point (120, 50), first control point (50, 120), second control point (300, 120), and the end point (230, 50).

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');

context.beginPath();
context.moveTo(120,50);
context.strokeStyle="blue"
context.bezierCurveTo(50,120,300,120,230,50);
context.stroke();

context.beginPath();
context.moveTo(120,50);
context.lineTo(50,120);
context.moveTo(300,120);
context.lineTo(230,50);
context.strokeStyle="green"
context.stroke();
</script>

bezierCurveTo

Line Styles

So far, you have drawn rectangles, lines, and arcs. It is now timely to pick up some tips on refining lines drawn on the canvas. HTML canvas provides four properties for refining the styles of lines drawn on the canvas – lineCap, lineJoin, lineWidth, and miterLimit.

Table 3: Line Styles Properties
Property Description / Code Snippets
lineCap The lineCap property sets or gets the style of the end caps for a line drawn on the canvas. It can take one of 3 values:

  • butt adds a flat edge to the end of a line which is the default
  • square adds a square cap to the end of a line
  • round adds a round cap to the end fof a line

The square and round styles will make the line slightly longer than the butt style.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.beginPath();
context.lineWidth=10;
context.lineCap="butt";
context.arc(88,100,30,0,1.5*Math.PI);
context.stroke();

context.beginPath();
context.lineCap="square";
context.arc(176,100,30,0,1.5*Math.PI);
context.stroke();

context.beginPath();
context.lineCap="round";
context.arc(264,100,30,0,1.5*Math.PI);
context.stroke();
</script>

linecap

lineJoin The lineJoin property sets or gets the style of the corner where 2 lines join. It can take one of 3 values:

  • bevel creates a bevel corner
  • round creates a round corner
  • miter creates a sharp corner which is the default
<script>
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.lineWidth=10;

context.beginPath();
context.lineJoin="bevel";
context.moveTo(110,50);
context.lineTo(30,100);
context.lineTo(110,150);
context.closePath();
context.stroke();

context.beginPath();
context.lineJoin="round";
context.moveTo(220,50);
context.lineTo(140,100);
context.lineTo(220,150);
context.closePath();
context.stroke();

context.beginPath();
context.lineJoin="miter";
context.moveTo(330,50);
context.lineTo(250,100);
context.lineTo(330,150);
context.closePath();
context.stroke();
</script>

linejoin

lineWidth The lineWidth property sets or gets the width of a line in pixels. We have already seen its use in the previous examples.

context.lineWidth=10;
miterLimit The miterLimitproperty sets or gets the maximum miter length when the lineJoin property is set to “miter”. The miter length is defined as the distance between the inner corner and the outer corner where two lines meet. If the miter length exceeds the miterLimit value, the corner will be displayed as “bevel” type of lineJoin.

context.miterLimit=10;

Texts

HTML canvas is not only for drawing graphics but also texts. HTML provides 3 properties – font, textAlign, and textBaseline, for defining the different states of a text on the canvas. These are described in Table 4.

Table 4: Text Properties
Property Description / Code Snippets
font The font property sets or gets the font properties such as font-style, font-weight, font-size, and font-family for text content on the canvas. It follows the same syntax as the CSS font property.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="30px Verdana";
context.fillStyle="red";
context.fillText("Hello CodeProject!",30,100);
</script>

fillstyle

textAlign The textAlign property sets or gets the horizontal alignment for text content on the canvas. It can take one of 5 values: “start“, “end“, “right“, “left“, and “center“.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.strokeStyle='blue';
context.moveTo(170,20);
context.lineTo(170,180);
context.stroke();
context.font="15px Verdana";
context.fillStyle="red";
context.textAlign='start'; 
context.fillText('start',170,40);
context.textAlign='end'; 
context.fillText('end',170,70);
context.textAlign='right'; 
context.fillText('right',170,100);
context.textAlign='left'; 
context.fillText('left',170,130);
context.textAlign='center'; 
context.fillText('center',170,160);
</script>

textalign

textBaseline The textBaseline property sets or gets the vertical alignment for text content on the canvas. It can take one of 5 values: “top“, “bottom“, “middle“, “aplhabetic“, and “hanging“.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.strokeStyle='blue';
context.moveTo(5,100);
context.lineTo(345,100);
context.stroke();
context.font="15px Verdana";
context.textBaseline="top"; 
context.fillText("top",5,100); 
context.textBaseline="bottom"; 
context.fillText("bottom",50,100); 
context.textBaseline="middle"; 
context.fillText("middle",120,100); 
context.textBaseline="alphabetic"; 
context.fillText("alphabetic",190,100); 
context.textBaseline="hanging"; 
context.fillText("hanging",290,100); 
</script>

textbaseline

HTML canvas provides two methods – fillText() and strokeText(), for drawing texts on the canvas, and one method – measureText() for finding the width of a text on the canvas. These are described in Table 5.

Table 5: Text Methods
Method Description / Code Snippets
fillText() The fillText() method draws filled text on the canvas. The default color is black.The fillText() method takes 4 parameters:

  • the text to be drawn
  • x coordinate to start the text
  • y coordinate to start the text
  • an optional maxWidth of the text

All coordinates are relative to the origin, i.e the top left corner, of the canvas.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='30px Arial';
context.fillText('fillText at x:0, y:30',0,30);
context.fillText('fillText at x:20, y:60',20,60);
context.fillText('fillText at x:40, y:90',40,90);
</script>

filltext

strokeText() The strokeText() method draws text (no fill) on the canvas. The default color is black.The strokeText() method takes 4 parametes similar to fillText().

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='30px Arial';
context.strokeText('strokeText at x:0, y:30',0,30);
context.strokeText('strokeText at x:20, y:60',20,60);
context.strokeText('strokeText at x:40, y:90',40,90);
</script>

stroketext

measureText() The measureText() method takes a specified text as parameter and returns an object that contains the width of that text, in pixels.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='30px Arial';
var text='My waist line is ';
var obj=context.measureText(text);
context.fillText(text,0,100);
context.fillText(obj.width,obj.width,100);
</script>

measuretext

Visual Effects

HTML canvas provides a rich set of properties and methods for defining and manipulating the visual effects – colors, gradients, shadows, and patterns, of graphics and texts drawn on the canvas. Refer to Tables 6 and 7 for detailed description and code examples of the various visual effects properties and methods respectively.

Table 6: Visual Effects Properties
Property Description / Code Snippets
strokeStyle The strokeStyle property sets or gets the color, gradient, or pattern used to draw the path on the canvas.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="30px Verdana";
context.strokeStyle="red";
context.strokeText("Hello CodeProject!",30,100);
</script>

strokestyle

fillStyle The fillStyle property sets or gets the color, gradient, or pattern used to fill the drawing on the canvas.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="30px Verdana";
context.fillStyle="red";
context.fillText("Hello CodeProject!",30,100);
</script>

fillstyle

shadowColorshadowBlur The shadowColor property sets or gets the shadow color.The shadowBlur property sets or gets the blur level for shadows.Both methods are used together to create a shadow surrounding a drawing.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="40px Verdana";
context.shadowBlur=20;
context.shadowColor="black";
context.fillStyle="red";
context.fillText("It is Hazy!",60,100);
</script>

shadow

shadowOffsetX The shadowOffsetX property sets or gets the horizontal distance of the shadow from the drawing.shadowOffsetX=0 indicates that the shadow is right behind the drawing.shadowOffsetX=15 indicates that the shadow starts 15 pixels to the right of the drawing.shadowOffsetX=-15 indicates that the shadow starts 15 pixels to the left of the drawing.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="40px Verdana";
context.shadowBlur=20;
context.shadowOffsetX=15
context.shadowColor="black";
context.fillStyle="red";
context.fillText("It is Hazy!",60,100);
</script>

shadowoffsetx

shadowOffsetY The shadowOffsetY property sets or gets the vertical distance of the shadow from the drawing.shadowOffsetY=0 indicates that the shadow is right behind the drawing.shadowOffsetY=15 indicates that the shadow starts 15 pixels below the drawing.shadowOffsetY=-15 indicates that the shadow starts 15 pixels above the drawing.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font="40px Verdana";
context.shadowBlur=20;
context.shadowOffsetY=-15
context.shadowColor="black";
context.fillStyle="red";
context.fillText("It is Hazy!",60,100);
</script>

shadowoffsety

Table 7: Visual Effects Methods
Method Description / Code Snippets
createLinearGradient() The createLinearGradient() method creates a linear gradient object for filling rectangles, circles, lines, and texts on the canvas by assigning this object as the value to the strokeStyle or fillStyle properties of the respective graphics.The createLinearGradient() method takes 4 parameters:

  • x coordinate of the start point
  • y coordinate of the start point
  • x coordinate of the end point
  • y coordinate of the end point

All coordinates are relative to the origin, i.e the top left corner, of the canvas.

The createLinearGradient() method must work with the addColorStop() method (discussed later) to specify different colors and their respective positions in the gradient object.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var gradientHorizontal=context.createLinearGradient(12,50,112,50);
gradientHorizontal.addColorStop(0,"black");
gradientHorizontal.addColorStop(1,"white");
context.fillStyle=gradientHorizontal;
context.fillRect(12,50,100,100);
var gradientVertical=context.createLinearGradient(124,50,124,150);
gradientVertical.addColorStop(0,"black");
gradientVertical.addColorStop(1,"white");
context.fillStyle=gradientVertical;
context.fillRect(124,50,100,100);
var gradientDiagonal=context.createLinearGradient(236,50,336,150);
gradientDiagonal.addColorStop(0,"black");
gradientDiagonal.addColorStop(1,"white");
context.fillStyle=gradientDiagonal;
context.fillRect(236,50,100,100);
</script>

createLinearGradient

createRadialGradient() The createRadialGradient() method creates a circular gradient object for filling rectangles, circles, lines, and texts on the canvas by assigning this object as the value to the strokeStyle or fillStyle properties of the respective graphics.The createRadialGradient() method takes 6 parameters:

  • x coordinate of the center of the first circle
  • y coordinate of the center of the first circle
  • radius of the first circle
  • x coordinate of the center of the second circle
  • y coordinate of the center of the second circle
  • radius of the second circle

All coordinates are relative to the origin, i.e the top left corner, of the canvas.

The createRadialGradient() method must work with the addColorStop() method (discussed after this) to specify different colors and their respective positions in the gradient object.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var gradient1=context.createRadialGradient(0,100,5,130,100,140);
gradient1.addColorStop(0,"black");
gradient1.addColorStop(1,"white");
context.fillStyle=gradient1;
context.fillRect(12,50,100,100);
var gradient2=context.createRadialGradient(110,100,140,230,100,5);
gradient2.addColorStop(0,"white");
gradient2.addColorStop(1,"black");
context.fillStyle=gradient2;
context.fillRect(124,50,100,100);
var gradient3=context.createRadialGradient(240,40,5,310,150,150);
gradient3.addColorStop(0,"black");
gradient3.addColorStop(1,"white");
context.fillStyle=gradient3;
context.fillRect(236,50,100,100);
</script>

createRadialGradient

addColorStop() The addColorStop() method specifies the colors and their positions in a gradient object.The addColorStop() method takes 2 parameters:

  • a value between 0.0 and 1.0 that represents the position between start point and end point in a gradient
  • the color to display at that position

The addColorStop() method is used together with the createLinearGradient() or createRadialGradient()

You may call the addColorStop() method multiple times to add multiple colors to a gradient object. You need to call this method at least once in order to have a visible gradient.

The code below creates a rainbow by calling multiple addColorStop() methods.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var gradient=context.createLinearGradient(50,30,50,170);
gradient.addColorStop(0,"red");
gradient.addColorStop("0.1","orange");
gradient.addColorStop("0.3","yellow");
gradient.addColorStop("0.5","green");
gradient.addColorStop("0.7","blue");
gradient.addColorStop("0.9","indigo");
gradient.addColorStop(1,"violet");
context.fillStyle=gradient;
context.fillRect(50,30,250,140);
</script>

addColorStop

createPattern() The createPattern() method can be called to create a pattern by repeating some element like an image, video, or other <canvas> element in a specified direction on the canvas.The createPattern() method takes 2 parameters:

  • the element to use, e.g. an image
  • the direction to repeat the element. The direction can take one of the 4 values as follows:
    • no-repeat displays the pattern only once (no repeat)
    • repeat repeats the pattern both horizontally and vertically
    • repeat-x repeats the pattern only horizontally
    • repeat-y repeats the pattern only vertically

To try out the code below, you have to first replace “ico-pro-64.png” with your own image that is placed in the same location (folder) as this code file. In the code, the image file of “ico-pro-64.png” is assigned to an image object called “img”. The “//” is the comment tag in JavaScript for explaining code and is ignored by the browser.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
// create an image object called img
var img = new Image();
// assign 'ico-pro-64.png' to the source of img 
img.src = 'icn-pro-64.png';
// a JavaScript function
function draw(direction)
{
    context.clearRect(0,0,canvas.width,canvas.height); 
    var pattern=context.createPattern(img,direction);
    context.fillStyle=pattern;
    context.fillRect(0,0,350,200);
}
</script>
<br>
<button onclick="draw('no-repeat')">no-repeat</button> 
<button onclick="draw('repeat')">repeat</button> 
<button onclick="draw('repeat-x')">repeat-x</button> 
<button onclick="draw('repeat-y')">repeat-y</button>

createpattern

Images

We will take a look at how HTML canvas handles images. (Table 8)

Table 8: Drawing Image Method
Method Description / Code Snippets
drawImage() The drawImage() method draws an imported resource like image, video, or canvas onto the canvas. We will only deal with images in this article.The drawImage() method takes 4 parameters:

  • x coordinate to place the image
  • y coordinate to place the image
  • width of the image
  • height of the image

The last 2 parameters can be used to stretch or shrink the image.

The code below shrinks this CodeProject image logo250x135

var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var img = new Image();
img.src = 'logo250x135.gif';
img.onload=function(){
    context.drawImage(img,10,10,150,70);
}
</script>

drawimage

getImageData() The getImageData() method creates an ImageData object by copying the pixel data from a specified rectangle on a canvas.The getImageData() method takes 4 parameters:

  • x coordinate of the top left corner of the copied rectangle
  • y coordinate of the top left corner of the copied rectangle
  • width of the rectangle area to copy
  • height of the rectangle area to copy

The last 2 parameters can be used to capture only a part of the rectangle. See example below.

putImageData() The putImageData() method puts the pixel data from a specified ImageData object back onto the canvas.The putImageData() method takes 6 parameters:

  • ImageData object
  • x coordinate of the top left corner of the ImageData object
  • y coordinate of the top left corner of the ImageData object
  • x coordinate to place the ImageData object
  • y coordinate to place the ImageData object
  • width to draw the ImageData object
  • height to draw the ImageData object

The code below copies the mascot part of the CodeProject image and paste it in a different location on the canvas.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var img = new Image();
img.src = 'logo250x135.gif';
img.onload=function(){
    context.drawImage(img,10,10,150,70);
}
function copynpaste()
{
    var imgData=context.getImageData(10,10,50,70);
    context.putImageData(imgData,180,100);
}
</script>
<br>
<button onclick="copynpaste()">Copy and Paste</button>

<code><a href="http://www.peterleowblog.com/wp-content/uploads/2015/06/getputimagedata.png"><img class="aligncenter size-full wp-image-653" src="http://www.peterleowblog.com/wp-content/uploads/2015/06/getputimagedata.png" alt="getputimagedata" width="366" height="244" /></a>

createImageData() The createImageData() method creates a new ImageData object of rectangular shape.The createImageData() method takes 2 parameters:

  • width of the ImageData object
  • height of the ImageData object

Every pixel in an ImageData object contains the RGBA values:

  • R – The color red (from 0-255)
  • G – The color green (from 0-255)
  • B – The color blue (from 0-255)
  • A – The alpha channel (from 0-255; 0 means transparent and 255 fully visible)

The default RGBA is transparent black, i.e (0,0,0,0), so it is not visible on the canvas. You have to set the RGBA values for each pixel in order to be able to see the image. For that, you have to make use of the for loop in JavaScript to traverse through all the RGBA values of each pixel, that will be (width x height x 4) times.

The code below creates a ImageData object that is being copied to 2 locations with different alpha channel.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var imgData=context.createImageData(100,100);
for (var i=0;i<imgData.data.length;i+=4)
{
  imgData.data[i+0]=0;
  imgData.data[i+1]=255;
  imgData.data[i+2]=0;
  imgData.data[i+3]=255;
}
context.putImageData(imgData,50,50);

for (var i=0;i<imgData.data.length;i+=4)
{
  imgData.data[i+3]=60;
}
context.putImageData(imgData,200,50);
</script>

createimagedata

Transformations

We have been dealing with static graphics and images on the canvas. Can we make them come alive and do stuff like transformation of shapes and animation on the canvas? The answer is a resounding “Yes”! HTML canvas has provided five methods for performing transformations like scaling, rotating, moving, and skewing of drawing on the convas. By manipulating these methods skillfully using JavaScript, you can create interesting animations, such as the Bouncing on Canvas and Merry-Go-Round on Canvas.

You will have some fun going through the creation of these two animations. However, you have to first get acquainted with the various transformation methods before you can understand those code for animation later on. So hang on and hang in for a little while …

Table 9: Transformation Methods
Method Description / Code Snippets
scale() The scale() method scales a drawing horizontally and vertically. It takes 2 parameters:

  • a number specifying the proportion of scaling of the width
  • a number specifying the proportion of scaling of the height

A number of 0.5 means 50% of the original dimension, 1 means 100%, 2 means 200%, and so on.

When a drawing is scaled, its positioning will also be scaled in relation to the origin of the canvas.

The code below scales the same triangle by 200% twice.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
// Set the origin to 175, 0
// context.translate(175,0);
context.moveTo(10,10);
context.lineTo(10,40);
context.lineTo(40,10);
context.closePath();
context.stroke();
// Scale by 200%
context.scale(2,2);
context.moveTo(10,10);
context.lineTo(10,40);
context.lineTo(40,10);
context.closePath();
context.stroke();
// Scale by 200% again
context.scale(2,2);
context.moveTo(10,10);
context.lineTo(10,40);
context.lineTo(40,10);
context.closePath();
context.stroke();
</script>

scale

translate() The translate() method allows you to set the origin of the coordinates (x=0, y=0) of the canvas to other position. It takes 2 parameter:

  • a number specifying the x coordinate of the new origin
  • a number specifying the y coordinate of the new origin

In the code above, remove the “//” which is the comment tag in JavaScript from the following statement. Save and view it on the browser. The translate() method has set the origin of the canvas to (x=175, y=0) and you should observe that the positioning of the triangles has been shifted to accommodate the new origin. Subsequent drawngs on the canvas will reference this point as the origin.

context.translate(175,0);

translate

rotate() The rotate() method rotates the drawing around the origin of the coordinates of the canvas. You can use the translate() method to relocate the origin.The rotate() method takes one parameter, i.e. the angle of rotation in radian.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.fillStyle = "red";

context.fillRect(100,0,100,4);

context.rotate(22.2*Math.PI/180);
context.fillRect(100,0,100,4);

context.rotate(22.2*Math.PI/180);
context.fillRect(100,0,100,4);

context.rotate(22.2*Math.PI/180);
context.fillRect(100,0,100,4);

context.rotate(22.2*Math.PI/180);
context.fillRect(100,0,100,4);
</script>

rotate

transform() The transform() method is the jack-of-all-transformations of the canvas. It can scale, rotate, move, and skew.The transform() method takes 6 parameters:

  • scale the drawing horizontally
  • skew the drawing horizontally
  • skew the drawing vertically
  • scale the drawing vertically
  • Moves the the drawing horizontally
  • Moves the the drawing vertically

The transform() method will add on to any preceding transformations made by rotate(), scale(), translate(), or transform(). For example, if you have already set your drawing to scale by two, and you subsequently call the transform() method to scale your drawings by three, your drawings will eventually be scaled by five.

The first block of code below moves the rectangle to the right and skew it horizontally.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='12px Arial';
// Original
context.transform(1,0,0,1,0,0);
context.strokeRect(50,75,100,40);
context.fillText('Original', 79,98);
// Move horizontally
context.transform(1,0,0,1,150,0);
context.strokeRect(50,75,100,40);
context.fillText('Move Horizontally', 53,98);
// Skew horizontal
context.transform(1,0.3,0,1,0,0);
context.strokeRect(50,75,100,40);
context.fillText('Skew Horizontally', 53,98);
</script>

transform1

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='12px Arial';
// Original
context.transform(1,0,0,1,0,0);
context.strokeRect(125,20,100,40);
context.fillText('Original', 154,45);
// Move vertically
context.transform(1,0,0,1,0,100);
context.strokeRect(125,20,100,40);
context.fillText('Move Vertically', 138,35);
// Skew vertically on the last transformed rectangle
context.transform(1,0,0.5,1,0,0);
context.strokeRect(125,20,100,40);
context.fillText('Skew Vertically', 138,50);
</script>

transform2

setTransform() The setTransform() method does the same thing as the transform() method except for one difference – The setTransform() will ignore any preceding transformation and always acts on the original drawing.The code below moves the rectangle downward followed by skewing the original rectangle vertically. Compare the screenshot below with that above it, and you will understand the difference between transform() and setTransform() methods.

<script>
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
context.font='12px Arial';
// Original
context.transform(1,0,0,1,0,0);
context.strokeRect(125,20,100,40);
context.fillText('Original', 154,38);
// Move vertically
context.transform(1,0,0,1,0,100);
context.strokeRect(125,20,100,40);
context.fillText('Move Vertically', 138,43);
// Skew vertically on the original
context.setTransform(1,0,0.5,1,0,0);
context.strokeRect(125,20,100,40);
context.fillText('Skew Vertically', 138,50);
</script>

settransform

Making Things Happen

You have learned hard. Let’s see how you can make use of your new found knowledge of HTML canvas to create two simple animations on the canvas. Download and extract the html5canvas.zip to a location on your computer, e.g. c:\html5canvas. You will find these three files inside the extracted folder:

  • merry-go-round.html
  • bouncing_on_canvas.html
  • icn-pro-64.png

Merry-Go-Round on Canvas

merry-go-round
Figure 8: Merry-Go-Round

Open the merry-go-round.html with a text editor and enter the following code below the <title> tag within the <head> and </head> tag section of this document. Once you are done, save and launch it on a browser and you should see a moving Merry-Go-Round as shown in Figure 8.

<script>
    var canvas;
    var context;
    var second;

    function init() {
        second = 0;
        canvas = document.getElementById("canvas");
        context = canvas.getContext("2d");
        
        // Set a timer to run the draw() function every one second
        timer = setInterval(draw, 1000);
        return timer;
    }
    function draw() {
        // Clear the canvas
        canvas.width = canvas.width;
    context.beginPath();
        // Define font and draw texts
        context.font='20px Arial';
        context.fillText('12',137,50);
        context.fillText('3',201,110);
        context.fillText('6',143,161);
        context.fillText('9',88,110);
        // Draw a circle
        context.lineWidth = "5";
        context.arc(150, 100, 70, 0, 2 * Math.PI);
        context.stroke();
        context.lineWidth = "2";
        // Set origin of canvas to 150, 100
        context.translate(150, 100);
        context.moveTo(0, 0);
        // Rotate and draw a line
        context.rotate(6 * second * Math.PI / 180);
        context.lineTo(0, -60);
        context.stroke();
        // Increase one second         
        second = (second + 1) % 60;

    }
</script>

The logic of the code works as follows:

  • Start by declaring three variables – canvas, context, and second
  • Once the web page finishes loading, the init() function will be called to:
    • set the initial value of the second variable to 0
    • assign the id of the HTML canvas, i.e. “mycanvas” to the canvas variable
    • call the canvas’s getContext() method to pass a context object to the context variable
    • create and start a timer and set it to call the draw() function every one second
  • At the tick of every second, the draw() function will be called to:
    • clear the canvas surface
    • set the font and draw the 4 texts of ’12’, ‘3’, ‘6’, and ‘9’ at the respective location on the canvas using the fillText() method
    • set the lineWidth property to 5 and draw a circle using arc() and stroke() method on the canvas
    • set the origin of the canvas to the center of the circle
    • rotate and draw a line from the center of the circle
    • increase the value of second variable by 1, when it exceeds 60, reset it to zero

In the code, you will find some familiar methods and properties of the HTML canvas that you have learned before. Congratulation! You have just put your new found knowledge into making something happened.

Bouncing on Canvas

bouncingoncanvas
Figure 9: Bouncing on Canvas

You are now really to explore the next exercise on your own. Open the bouncing_on_canvas.html with a text editor and enter the following code below the <title> tag within the <head> and </head> tag section of this document. Once you are done, save and launch it on a browser and you should see a bouncing CodeProject Professional as shown in Figure 9. The code has been adequately commented. I shall leave it to you as homework to interpret the logic of the code.

<script>
    var canvas;
    var context;
    var dx = 2;  // Rate of change for x coordinate
    var dy = 1;  // Rate of change for y coordinate
    var point;
    var timer;
    var imgData;
    var coords;

    function point(x, y) {
        this.x = x;
        this.y = y;
    }

    function init() {
        imgData = new Image();
        imgData.src = 'icn-pro-64.png';

      // Generate initial start point of x and y for the image on the convas
        point = new point(Math.random() * 200, Math.random() * 150)
        canvas = document.getElementById("canvas");
        context = canvas.getContext("2d");

      // Start a timer to call the draw() method every 10 milliseconds
        timer = setInterval(draw, 10);
        return timer;
    }

    function draw() {
        canvas.width = canvas.width;
        context.lineWidth = "5";
        context.strokeStyle = "red";
        context.rect(0, 0, canvas.width, canvas.height);
        context.stroke();
      
      // Make sure the image stays within the width of the canvas
        if (point.x + imgData.width + dx > canvas.width || point.x + dx < 0) dx = -dx; // Make sure the image stays within the breadth of the canvas if (point.y + imgData.height + dy > canvas.height || point.y + dy < 0)
            dy = -dy;

      // Increment x value by dx
        point.x += dx;
      // Increment y value by dy
        point.y += dy;
      // Draw the image at the new point of x and y
        context.drawImage(imgData, point.x, point.y);
      // Display the x and y coordinates
        coords = "x: " + parseInt(point.x) + "  y: " + parseInt(point.y);
        document.getElementById("coordinates").innerHTML = coords;
    }
</script>

End of Affair

I hope you have enjoyed the affair with HTML canvas. Unfortunately, all good things must come to an end. However, the end of one thing is the beginning of another. So stay tuned …

Reference

Download

Posted in HTML / CSS Tagged with: , ,