Canvas Cookbook - Sample Chapter

Download as pdf or txt
Download as pdf or txt
You are on page 1of 34

Fr

ee

Canvas Cookbook

The recipes are simple yet creative and build on each other. At every step, the book inspires the reader
to develop his/her own recipes. From basic to advanced, every aspect of Canvas API has been covered
to guide readers to develop their own application, presentation, or game.

What this book will do


for you...
Draw basic shapes such as lines, arcs,

curves, and text using the coordinate system


Learn about the animation cycle and use

it to animate shapes
Grasp the knowledge required to create

Canvas Cookbook

With the growing popularity of HTML5 Canvas, this book offers tailored recipes to help you develop
portable applications, presentations, and games.

Sa

pl
e

a particle system and use it


Apply a variety of effects to images

and videos

Inside the Cookbook...

Discover the use of event listeners


Use Canvas to represent data in the form

of graphs and charts


Learn all about 3D development, from

building 3D objects to animating them

A selection of the most important tasks

and problems

Carefully organized instructions to solve

problems efficiently

Implement your knowledge to develop a game

Clear explanations of what you did

Understand the interoperability and

Solutions that can be applied to solve

deployment of recipes on different


browsers and devices

real-world problems

$ 44.99 US
28.99 UK

community experience distilled

P U B L I S H I N G

Quick answers to common problems

A straightforward and easy-to-follow format

Bhushan Purushottam Joshi

to make recipes interactive

Canvas Cookbook
Over 80 simple but creative and structured recipes to explore
the capabilities of HTML5 Canvas

Prices do not include


local sales tax or VAT
where applicable

P U B L I S H I N G

Visit www.PacktPub.com for books, eBooks,


code, downloads, and PacktLib.

Bhushan Purushottam Joshi

In this package, you will find:

The author biography


A preview chapter from the book, Chapter 2 'Shapes and Composites'
A synopsis of the books content
More information on Canvas Cookbook

About the Author


Bhushan Purushottam Joshi is a teacher of computer science and has around
11 years of experience in teaching. He started his career as a programmer in a software
firm but found true joy in teaching. He is a teacher by choice and not by chance. He teaches
computer science courses such as MCA, MSc IT, BSc IT, and BSc CS at various colleges in
Mumbai. He is a master at presenting technical as well as conceptual subjects in the most
simplified manner. He has exemplary skill at relating daily life examples to technical concepts,
which facilitates understanding of the subject matter. He enjoys teaching technical as well
as conceptual subjects such as web design, Java, C#, C++, operating systems, computer
networks, data structures, and ethical hacking. He is quite popular and appreciated among
students for his able guidance in their project work.
Canvas Cookbook is his first sincere attempt to present the usage of HTML5 Canvas in
conjunction with JavaScript and CSS to build simple and crisp recipes.

Preface
The world of gaming is very competitive, and day by day the technology is evolving and
making things easier for users. HTML5 is a recent standard, which is flexible, interactive,
and portable. It is supported by most browsers. This makes HTML5 a good language for
developing applications with a wider reach.
The Canvas element in HTML5 is quite interesting as it allows programmers to render
whatever they can imagine. Canvas allows users to draw 2D and 3D objects and render
animation. HTML5 Canvas is therefore a suitable technology for developing applications
and games for a variety of devices.
However, without a scripting language, HTML5 Canvas, is of limited use. A scripting language
such as JavaScript is necessary to make use of HTML5 Canvas and is at the heart of any
application or game.
Any application without style is an ordinary application that will not catch the eye of a user.
Styling is important when it comes to developing applications commercially. It adds richness
to the application. CSS helps developers do this.
This book is all about the usage of HTML5 Canvas, JavaScript, and CSS in the development
of various recipes. The book starts with basic drawings on Canvas, graduates to animation
and 3D rendering, and culminates with the development of games that can run on different
devices. The recipes in each chapter are simple and crisp. The last few chapters exhibit the
usage of third-party libraries such as Three.js and Phaser.js.
All recipes are supported with a precise explanation to inspire the reader to develop his or
her own recipes.

Preface

What this book covers


Chapter 1, Paths and Text, is a simple chapter where you can view basic recipes to draw lines,
arcs, curves, and text. It introduces the use of the Canvas API to render drawings.
Chapter 2, Shapes and Composites, introduces various shapes such as triangles, rectangles,
circles, and ellipses. Coloring and styling is also demonstrated in a few recipes. You will find
here exciting recipes rendering styled text and various types of composite.
Chapter 3, Animation, uses the drawings made in the previous chapter and adds some actions
to them. It introduces a systematic approach toward animation. It covers basic movements such
as linear motion, acceleration, oscillation, and its implementation through impressive recipes.
Chapter 4, Images and Videos, reveals the rendering of images and videos. The recipes
show the clipping and cropping of images. Images on canvas are the basic foundation for
any application or game.
Chapter 5, Interactivity through Events, introduces event handling. It encompasses events
captured through input devices such as the mouse, keyboard, and touch. You will be able to
create a simple game at the end of this chapter.
Chapter 6, Creating Graphs and Charts, displays different types of graph and chart. These are
ideal for any data presentation. Here, I will show you to draw simple x and y axes and then plot
different equations on them. You will learn to draw a bar chart and a pie chart.
Chapter 7, 3D Modeling, will show you the rendering of 3D objects. It will introduce you to an
open source library named Three.js, used to draw various shapes such as cubes, spheres,
cylinders, and toruses.
Chapter 8, Game Development, explains the complete procedure for developing a game.
It is time to assemble all the nuts and bolts. I introduce here another open source library
Phaser.js, which is one of the popular libraries for game development. You will learn various
game stages, playing audio, creating and using sprites, and much more.
Chapter 9, Interoperability and Compatibility, is just an extension to the previous chapter,
which highlights the deployment of the game on a mobile phone. You will encounter the
use of CSS to enhance the look and feel of the game.

Shapes and Composites


This chapter explains to draw various shapes. These basic building blocks are further
combined to create desired drawings. In this chapter we will cover:

Drawing rectangles

Drawing triangles

Drawing circles

Drawing gradients

Working with custom shapes and styles

Demonstrating translation, rotation, and scaling

Drawing an ellipse

Saving and restoring canvas state

Demonstrating compositions

Drawing a mouse

Introduction
In this chapter, we will learn how to draw rectangles, triangles, circles, ellipses, and custom
shapes. Also, we will learn to fill gradients, translation, rotation, and scaling to be applied on
these shapes.
The recipe structure will be a bit different in this chapter. We will have the JavaScript code in
a separate file and this file will be embedded in the HTML code at run-time. In the previous
chapter, the complete recipe was in a single file (.html file). However, in this chapter, a single
recipe will comprise two different files:

An HTML file

A JavaScript file
39

Shapes and Composites


Also, the can (canvas) and ctx (context) objects are created within the init() function
and the reference to ctx (context) is passed to the different functions called within init().

Drawing rectangles
There are three different functions in the canvas API to draw rectangles. They are:

rect(xPos,yPos,width,height)

fillRect(xPos,yPos,width,height)

strokeRect(xPos,yPos,width,height)

Let's see these all together in a single recipe. So here is the output of our first recipe:

How to do it
The output that shows three different rectangles, uses a call to three different functions,
which are explained further. The recipe is as follows.
An HTML file that includes the canvas element:
<html>
<head>
<title>Rectangles</title>
<script src="Rectangles.js"></script>
</head>
<body onload="init()" bgcolor="#FFFFCC">
<canvas id="canvas" width="250" height="200" style="border:2px solid
blue;" >
your browser does not support canvas
</canvas>
<H1>Rectangles</H1>
</body>
</html>

40

Chapter 2
The JavaScript file as mentioned in the <script> tag in the previously given code:
function init()
{
var canvas = document.getElementById("canvas");
if(canvas.getContext)
{
// Color of drawing, fillStyle is this color
var ctx = canvas.getContext("2d");
// Draw a square(rectangle with same sides)
// from top left corner x,y, width, height
ctx.strokeStyle="purple"
ctx.rect(10,10,70,50);
ctx.fillStyle="lightgreen";
ctx.fill();
ctx.stroke();
//draw another rectangle
ctx.fillStyle="crimson";
ctx.fillRect (50,25, 100,100);
//draw yet another
ctx.strokeStyle="blue";
ctx.lineWidth=10;
ctx.strokeRect(100,60,80,130);
}
}

How it works...
This is what you can observe in the output of the recipe:

The top-most blue bordered rectangle is drawn using the strokeRect() function

The second red colored rectangle is drawn using the fillRect() function

The first green colored rectangle is drawn using the rect() and fill() functions

The property fillStyle decides the color for filling the rectangle. The strokeStyle
property decides the color of the border.

41

Shapes and Composites


The three rectangles drawing functions accept the following parameters:
Parameter
X

The x coordinate of the upper-left corner of the rectangle

Description

The y coordinate of the upper-left corner of the rectangle

Width

The width (in pixels) of the rectangle

Height

The height (in pixels) of the rectangle

Diagrammatically it can be shown as follows:

Drawing triangles
There is no direct function to draw a triangle using the canvas API. But we do have the other,
simpler functions that, together, allow us to draw different shapes. A triangle is a combination
of three joined lines. Let's see this in our new example. The output is quite simple and looks
like this:

42

Chapter 2

How to do it
The triangle is drawn by calling two basic functions, namely moveTo() and lineTo(). Here
is the recipe.
The HTML file:
<html>
<head>
<title>triangles</title>
<script src="triangles.js"></script>
</head>
<body onload="init()">
<canvas id="MyCanvasArea" width="200" height="200" style="border:2px
solid blue;" >
your browser does not support canvas
</canvas>
<H1>Triangle</H1>
</body>
</html>

The JavaScript file:


function init(){
var can = document.getElementById("MyCanvasArea");
if(can.getContext)
{
var context=can.getContext("2d");
drawTriangle(context,100,20,100,100,"forestgreen");
}
}
function drawTriangle(ctx, x, y,Width,Height,color){
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + Width / 2, y + Height);
ctx.lineTo(x - Width / 2, y + Height);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}

43

Shapes and Composites

How it works...
The init() function calls the drawTriangle() method. The parameters passed for drawing
the triangle are the X position, Y position, the width and height of the triangle, and the color for
filling the triangle. The triangle drawing starts by calling the beginPath() function and ends
on the call of the endPath() function. The moveTo() function takes you to the position from
where you want to draw the triangle. Then, using the width and height, a line is drawn using
the simple lineTo() function. Another line is drawn from there. The closePath() function
completes the triangle by joining the last coordinate with the first one. The fillStyle
property and fill() method does the job of filling the triangle with a color.

There's more...
Try the following:

Instead of filling the triangle, only draw the triangle with boundaries. Use
strokeStyle and stroke() before closePath().

Place the stroke() method call after closePath() and check the output.

Drawing circles
Again, there is no direct function to draw a circle. It should be drawn using the function for
drawing an arc. We saw a drawing of a circle in the previous chapter through the example
of drawing arc2. The output of the circle recipe looks like this:

44

Chapter 2

How to do it
The recipe is very simple. It calls the drawCircle() function in a loop to draw multiple
circles as you see here. The recipe is as follows.
The HTML code:
<html>
<head>
<title>circles</title>
<script src="circles.js"></script>
</head>
<body onload="init()">
<canvas id="MyCanvasArea" width="300" height="300" style="border:2px
solid blue;" >
your browser does not support canvas
</canvas>
<h1>Circles</h1>
</body>
</html>

The JavaScript code:


function init(){
var can=document.getElementById("MyCanvasArea");
var ctx=can.getContext("2d");
//call to the function to draw Circle
for(i=1,x=15,y=20,r=10;i<=6;i++,x+=r*2,y+=r*2,r=r+10){
drawCircle(ctx,x,y,r,"forestgreen","lightyellow");
}
}
function drawCircle(ctx,xPos, yPos, radius, borderColor, fillColor){
var startAngle =
0 * (Math.PI/180);
var endAngle
= 360 * (Math.PI/180);
var radius = radius;
ctx.strokeStyle = borderColor;
ctx.fillStyle
= fillColor;
ctx.lineWidth
= 5;
ctx.beginPath();
ctx.arc(xPos, yPos, radius, startAngle, endAngle, false);
ctx.fill();
ctx.stroke();
}
45

Shapes and Composites

How it works...
The init() function calls the drawCircle() function, which in turn calls the arc() function
with the necessary parameters to draw an arc from 0 degrees to 360 degrees, which completes
a circle. Since the start and end angle to be passed in the arc() method must be in radians,
the degrees are converted to radians. The formula used is: radian = degree * /180. The border
color and fill style are also specified.
The x and y coordinates and the radius value are specified in the for loop. The loop runs six
times, drawing six circles at different positions and of different sizes. In every iteration, the
value of x, y, and r changes (namely, the position and radius).

There's more...
Try the following:

Remove the statement x+=r*2 and see the output

Remove the statement y+=r*2 and see the output

Remove the statement r=r+10 and see the output

Change the border color and fill color

Drawing gradients
Here we implement some effects. Applying a gradient is quite a colorful activity. The output of
our recipe demonstrating gradients looks like this:

46

Chapter 2

How to do it
The recipe uses four new methods, namely createRadialGradient(),
createLinearGradient(), addColorStop(), and rgb(). The recipe is as follows.
The HTML code:
<html>
<head>
<title>Gradients</title>
<script src="gradients.js"></script>
</head>
<body onload="init()">
<canvas id="MyCanvasArea" width="500" height="200" style="border:2px
solid blue;" >
your browser does not support canvas</canvas>
<h1>Radial and Linear Gradient</h1>
</body>
</html>

The JavaScript code:


function init()
{
var can=document.getElementById("MyCanvasArea");
var ctx=can.getContext("2d");
//coordinates of center of 1st circle and a radius
var x1 = 100;
// x of 1. circle center point
var y1 = 100;
// y of 1. circle center point
var r1 = 30;
// radius of 1. circle
//coordinates of center of 2nd circle and a larger radius
var x2 = 100;
var y2 = 100;
var r2 = 100;
var radGrad=ctx.createRadialGradient(x1,y1,r1,x2,y2,r2);
radGrad.addColorStop(0,'rgb(110,120, 255)');//bluish shade
radGrad.addColorStop(0.5,'rgb(255,155,20)');//orange shade
radGrad.addColorStop(1,'rgb(0, 255,220)');//green shade
ctx.fillStyle = radGrad;
ctx.fillRect(0,0, 200,200);
//drawing the horizontal linear gradient
var linGrad1 = ctx.createLinearGradient(220,0,320,0);
linGrad1.addColorStop(0,'rgb(255,0,0)');//red
47

Shapes and Composites


linGrad1.addColorStop(0.5,'rgb(0,255,0)');//green
linGrad1.addColorStop(1,'rgb(0,0,255)');//blue
ctx.fillStyle = linGrad1;
ctx.fillRect(220,10,100, 100);
//drawing the vertical linear gradient
var linGrad2 = ctx.createLinearGradient(0,0,0,100);
linGrad2.addColorStop(0 , 'rgb(255,0,110)');
linGrad2.addColorStop(0.5, 'rgb(0,110,255)');
linGrad2.addColorStop(1 , 'rgb(110,255,0)');
ctx.fillStyle = linGrad2;
ctx.fillRect(350, 10, 100, 100);
}

How it works...
The new methods and their purpose are listed in the following table:
Function
addColorStop(offset,color)

createLinearGradient(xPos1,yP
os1,xPos2,yPos2)

Description
This method can be called for a gradient to add
the color and the value of offset (between 0 and 1)
to indicate the percentage of color to be applied in
the area specified for the gradient.
This function allows the creation of the area in
which the gradient can be applied. The area can
be created by specifying the coordinates.
Note: If x1 and x2 are the same then the vertical
gradient can be applied. If y1 and y2 are the
same, a horizontal gradient can be applied.

createRadialGradient(x1,y1,r1
,x2,y2,r2)

(x1,y1) is the center of the starting circle and


(x2,y2) is center of the ending circle. r1 and r2
are the radius of these two circles.

rgb(value_for_red,value_for_
green,value_for_blue)

The value for any of the colors can be an integer


between 0 and 255. The combination of these
three colors creates the resultant color and can be
applied in the addColorStop() function.

48

Chapter 2

Radial gradient
Observe the first rectangle in the output, and you will understand that at the center of the circle
there is a bluish shade. The next concentric circle has an orange shade, and towards the outer
side of the circle you will observe a greenish shade. This is because of the following snippet:
radGrad.addColorStop(0,'rgb(110,120, 255)');//bluish shade
radGrad.addColorStop(0.5,'rgb(255,155,20)');//orange shade
radGrad.addColorStop(1,'rgb(0, 255,220)');//green shade

But then, what is radGrad? radGrad is the radial gradient created using the arguments
specifying the centers of two circles (starting and ending) and their radius. radGrad is
created by calling the createRadialGradient() function.

Linear gradient
The linear gradient is created by calling the createLinearGradient() function. The
function allows specifying the starting coordinate and the ending coordinate. This defines
a rectangular portion where the gradient is applied. Any drawing in this area will be filled
with the gradient colors available in that area. If the drawing is drawn beyond the gradient
area, then the color towards that end of the gradient will be applied to the drawing. You will
definitely understand this paragraph when you see our next recipe.
In the current recipe there are two types of gradient, namely horizontal and vertical.
The following code applies the horizontal gradient:
var linGrad1 = ctx.createLinearGradient(220,0,320,0);
linGrad1.addColorStop(0,'rgb(255,0,0)');//red
linGrad1.addColorStop(0.5,'rgb(0,255,0)');//green
linGrad1.addColorStop(1,'rgb(0,0,255)');//blue

Observe the coordinates. The y1 and y2 values are the same. It means that the gradient is
along the x axis, the width being 100(320-220). So the red, green, and blue colors are
applied in this region. Now, a rectangle with an x coordinate between 220 and 320 is drawn
on the canvas, and can be filled with the gradient specified previously. This is done by the
following code in our recipe:
ctx.fillStyle = linGrad1;
ctx.fillRect(220,10,100, 100);

Note that the coordinates of the rectangle starting from 220, 10 are inside
the region specified in the gradient linGrad1.

Technically, the vertical gradient is not much different from the horizontal gradient. Here, the
x values of both the coordinates specified in the createLinearGradient() function are
the same, while the y values differ, specifying the region along the y axis.
49

Shapes and Composites

There's more...
Try the following:

For the radial gradient, change the value of y2 (y value of the center coordinates of
the second circle) to 50

Change the values in the rgb() function

Working with custom shapes and styles


Until now we have learned how to draw basic shapes such as lines, arcs, curves, andrectangles.
However, using this knowledge you can draw various shapes, such as a pentagon, a hexagon,
a cloud, and so on. Our new recipe shows you how. In addition, it also shows you the different
ways of filling these shapes with different effects:
The output of our recipe is as follows:

How to do it
The recipe is given as follows.
The HTML code:
<html>
<head>
<title>Clouds</title>
<script src="clouds.js"></script>
</head>
<body onload="init()">
<canvas id="MyCanvasArea" width="800" height="300" style="border:2px
solid blue;" >
your browser does not support canvas</canvas>
<h1>Cloudy Sky</h1>
</body>
</html>
50

Chapter 2
The JavaScript code:
var can;
var ctx;
var color;
function init()
{
can=document.getElementById("MyCanvasArea");
ctx=can.getContext("2d");
//set the gradient
color=ctx.createLinearGradient(0, 0, can.width, can.height);
color.addColorStop(0,'white');
color.addColorStop(0.5,'grey');
color.addColorStop(1,'black');
//draw the first cloud
var xfactor=0;
drawCloud(xfactor);
//draw the second cloud
xfactor=150;
drawCloud(xfactor);
//draw third cloud
xfactor=xfactor+150;
drawCloud(xfactor);
//draw the fourth cloud
xfactor=xfactor+150;
drawCloud(xfactor);
//draw the fourth cloud
xfactor=xfactor+150;
drawCloud(xfactor);
//rectangle to just show the gradient
ctx.rect(0,150,can.width,130);
ctx.fill();
}
function drawCloud(xfactor)
{
ctx.beginPath();
51

Shapes and Composites


ctx.moveTo(50+xfactor,50);
ctx.bezierCurveTo(0+xfactor,100,100+xfactor,100,100+xfactor,90);
ctx.bezierCurveTo(100+xfactor,130,170+xfactor,130,
150+xfactor,70);
ctx.bezierCurveTo(190+xfactor,10,140+xfactor,10,120+xfactor,30);
ctx.bezierCurveTo(120+xfactor,10,20+xfactor,10,50+xfactor,50);
ctx.closePath();
ctx.fillStyle=color;
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = 'grey';
ctx.stroke();
}

How it works...
The function drawCloud() is called multiple times in the code. The xfactor variable is
changed to shift the cloud along the x axis.

Demonstrating translation, rotation, and


scaling
These three 2D transformation techniques are quite useful:

Translation means changing the position of the origin (0,0) of the context

Rotation means moving the context by a particular angle

Scaling means changing the size of the drawing along the x axis and/or along
the y axis

All three techniques are demonstrated in our new recipe whose output looks like this:

52

Chapter 2

How to do it
The following code does the job.
The HTML code:
<html>
<head>
<title>Translate, rotate and scale</title>
<script src="TRS.js"></script>
</head>
<body onload="drawTRS();">
<table border="1" align="center" bgcolor="lightyellow">
<caption><b>Translation, Rotation and Scaling</b></caption>
<tr>
<td><canvas id="can0" width="300" height="200"></canvas><br/>
<b><label id="lbl0"></label></b>
</td>
<td><canvas id="can1" width="300" height="200"></canvas><br/>
<b><label id="lbl1"></label></b>
</td>
<td><canvas id="can2" width="300" height="200"></canvas><br/>
<b><label id="lbl2"></label></b>
</td>
</tr>
</table>
</body>
</html>

The JavaScript code:


function drawTRS(){
var label0 = document.createTextNode('TRANSLATION');
document.getElementById('lbl0').appendChild(label0);
var ctx0 = document.getElementById('can0').getContext('2d');
ctx0.fillStyle="blue";
ctx0.fillRect(10,10,100,100);
ctx0.translate(120,70);
//translation
ctx0.fillRect(10,10,100,100);
var label1 = document.createTextNode('ROTATION');
document.getElementById('lbl1').appendChild(label1);

53

Shapes and Composites


var ctx1 = document.getElementById('can1').getContext('2d');
ctx1.fillStyle="red";
ctx1.fillRect(50,10,100,100);
ctx1.rotate(20*Math.PI/180);//rotate by 20 degrees
ctx1.fillStyle="green";
ctx1.fillRect(180,10,100,100);
var label2 = document.createTextNode('SCALING');
document.getElementById('lbl2').appendChild(label2);
var ctx2 = document.getElementById('can2').getContext('2d');
ctx2.fillStyle="yellowgreen";
ctx2.fillRect(10,10,50,50);
ctx2.scale(2,2);
//scaling
ctx2.fillStyle="crimson";
ctx2.fillRect(40,20,50,50);
}

How it works...
There are three different functions to do these three tasks of translation, rotation, and scaling:

The translation happens by calling the translate (xPos,yPos) function. This


shifts the origin of the context, for example (0,0), to other coordinates as specified
in the function. In our case it is (120,70). This coordinate is considered as the
origin and then the shape is drawn. Note that the coordinates passed in both the
fillRect() function with respect to the context ctx0 are the same.

The rotation happens by calling the rotate (angle) function. The angle has to be in
radians. Calls to this function shift the origin in an angular direction, depending on
the value. In our recipe, the angle is 20 degrees and the shift is clockwise.
Just imagine pressing both of your palms on a sheet of paper and moving your hands
in a clockwise direction by a small angle. Thus, the paper will also change its angle.

Scaling happens by calling one simple function named scale (xScale,yScale).


The parameters passed in this function decide the change in size along the x axis
and the y axis. The values can be fractional. In our recipe the scaling is twice the
original size.

There's more...
Try the following:

54

Change the parameters of translate, rotate, and scale functions in the


given recipe.

Chapter 2

Drawing an ellipse
Drawing an ellipse is just an implementation of translation and scaling. The output is
quite simple:

How to do it
The recipe goes like this.
The HTML code:
<!DOCTYPE HTML>
<html>
<head>
</head>
<body onload="init()">
<canvas id="myCanvas" width="578" height="200" style="border:3px solid
blue"></canvas>
<script src="ellipse.js">
</script>
</body>
</html>

The JavaScript code:


function init()
{
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = 0;
var centerY = 0;
var radius = 50;
// translate context
context.translate(canvas.width / 2, canvas.height / 2);
// scale context horizontally
context.scale(2, 1);
55

Shapes and Composites


// draw circle which will be stretched into an ellipse
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 5;
context.strokeStyle = 'black';
context.stroke();
}

How it works...
Observe that the translate() and scale() functions are used to do this drawing. First,
the origin is shifted by using the translate() function. Later, the scaling is applied. And
then a circle is drawn using the arc() function.

Saving and restoring canvas state


This recipe is based on the concept of stack. You can imagine a stack of books. Say, for
example, I have to pick up a book from a stack of three books. It's always logical and easy
to pick up the top-most book, read it, and keep it aside. Then I pick another book from the
two-book stack, read it, and keep it aside. Then I pick the last book, read it, and keep it aside.
States of canvas work in a similar way. Let's see the output of the recipe:

56

Chapter 2

How to do it
The recipe for the previous output goes like this.
The HTML code:
<html>
<head>
<title>Canvas Save And Restore</title>
<script src="CanvasSaveRestore.js"></script>
</head>
<body onload="CanvasSaveRestore()">
<canvas id="MyCanvasArea" width="500" height="200" style="border:2px
solid blue;" >
your browser does not support canvas
</canvas>
<h1>Canvas Save And Restore</h1>
</body>
</html>

The JavaScript code:


function CanvasSaveRestore()
{
can=document.getElementById("MyCanvasArea");
ctx=can.getContext("2d");
ctx.fillStyle = 'cadetblue';
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowBlur
= 4;
ctx.shadowColor
= 'rgba(204, 204, 204, 0.5)';
ctx.fillRect(20,0,15,150);
ctx.save();
ctx.fillStyle = 'burlywood';
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.shadowBlur
= 4;
ctx.shadowColor
= 'rgba(204, 204, 204, 0.5)';
ctx.fillRect(50,0,30,150);
ctx.save();

57

Shapes and Composites


ctx.fillStyle = 'coral';
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 15;
ctx.shadowBlur
= 4;
ctx.shadowColor
= 'rgba(204, 204, 204, 0.5)';
ctx.fillRect(100,0,45,150);
ctx.save();
ctx.restore();
ctx.beginPath();
ctx.rect(200,10,50,50);
ctx.closePath();
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.rect(300,10,50,50);
ctx.closePath();
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.rect(400,10,50,50);
ctx.closePath();
ctx.fill();
}

How it works...
The first rectangle is drawn using certain styles and effects. This state of canvas is stored in
the stack at position 1 (refer to the output). Then the other rectangle is drawn with different
settings and this state is saved at position 2, which is above 1. The same happens with the
third triangle. The saving of state happens using the save() method.
While restoring the state of canvas from the stack, whatever is on the top of the stack is
removed and used. So the state at position 3 on the stack is used to draw the next rectangle.
The next rectangle then uses the state at position 2, as the state at position 3 has already been
removed and used. Finally, the state stored at position 1 is used to draw the last rectangle.

58

Chapter 2

Demonstrating composites
Composite operations allow you to change how the new content is drawn on an HTML5
<canvas> element. New things appear over whatever has already been drawn. By changing
the global composite operation, you can draw new shapes behind existing ones, perform
boolean operations, and do some other neat things.
The two main components in a compositing operation are the destination and the source.
The destination is what is already on the canvas, and the source is what is getting drawn
onto the canvas.
The following is a description for each possible composite operation available with the
HTML5 Canvas API, where the text Be happy represents the source (S), and the green
rectangle represents the destination (D). To further develop your understanding of composite
operations, it helps to look at the corresponding operation while reading each description:
Operation

Description

source-atop (S atop D)

Display the source image wherever both images are


opaque. Display the destination image wherever the
destination image is opaque but the source image is
transparent. Display transparency elsewhere.

source-in (S in D)

Display the source image wherever both the source image


and destination image are opaque. Display transparency
elsewhere.

source-out (S out D)

Display the source image wherever the source image is


opaque and the destination image is transparent. Display
transparency elsewhere.

source-over (S over D, default)

Display the source image wherever the source image is


opaque. Display the destination image elsewhere.

destination-atop (S atop D)

Display the destination image wherever both images are


opaque. Display the source image wherever the source
image is opaque but the destination image is transparent.
Display transparency elsewhere.

destination-in (S in D)

Display the destination image wherever both the


destination image and source image are opaque. Display
transparency elsewhere.

destination-out (S out D)

Display the destination image wherever the destination


image is opaque and the source image is transparent.
Display transparency elsewhere.

destination-over (S over D)

Display the destination image wherever the destination


image is opaque. Display the destination image elsewhere.

59

Shapes and Composites


Operation

Description

lighter (S plus D)

Display the sum of the source image and destination image.

xor (S xor D)

Exclusive OR of the source image and destination image.

copy (D is ignored)

Display the source image instead of the destination image.

In short, the composites operate like this:


source-over

destination + source

destination-over

source + destination

source-in

destination & source

destination-in

source & destination

source-out

source destination

destination-out

destination source

source-atop

destination + (source & destination)

destination-atop

source + (destination & source)

lighter

destination + source + lighter (source & destination)

darker

destination + source + darker (source & destination)

xor

source ^ destination

copy

source

Let's see the output to understand the different composite types:

60

Chapter 2

How to do it
The recipe goes like this.
The HTML code:
<html>
<head>
<title>Composites</title>
<script src="composites.js"></script>
</head>
<body onload="drawComposites();">
<table border="1" align="center" bgcolor="lightyellow">
<caption><b>Composites with Shapes</b></caption>
<tr>
<td><canvas id="can0" width="200" height="100"></canvas><br/>
<b><label id="lbl0"></label></b>
</td>
<td><canvas id="can1" width="200" height="100"></canvas><br/>
<b><label id="lbl1"></label></b>
</td>
<td><canvas id="can2" width="200" height="100"></canvas><br/>
<b><label id="lbl2"></label></b>
</td>
</tr>
<tr>
<td><canvas id="can3" width="200" height="100"></canvas><br/>
<b><label id="lbl3"></label></b>
</td>
<td><canvas id="can4" width="200" height="100"></canvas><br/>
<b><label id="lbl4"></label></b>
</td>
<td><canvas id="can5" width="200" height="100"></canvas><br/>
<b><label id="lbl5"></label></b>
</td>
</tr>

61

Shapes and Composites


<tr>
<td><canvas id="can6" width="200" height="100"></canvas><br/>
<b><label id="lbl6"></label><b>
</td>
<td><canvas id="can7" width="200" height="100"></canvas><br/>
<b><label id="lbl7"></label></b>
</td>
<td><canvas id="can8" width="200" height="100"></canvas><br/>
<b><label id="lbl8"></label></b>
</td>
</tr>
<tr>
<td><canvas id="can9" width="200" height="100"></canvas><br/>
<b><label id="lbl9"></label></b>
</td>
<td><canvas id="can10" width="200" height="100"></canvas><br/>
<b><label id="lbl10"></label></b>
</td>
<td><canvas id="can11" width="200" height="100"></canvas><br/>
<b><label id="lbl11"></label></b>
</td>
</tr>
</table>
</body>
</html>

The JavaScript code:


var compositeTypes = ['source-over','source-in','sourceout','source-atop','destination-over','destination-in','destinationout','destination-atop','lighter','darker','copy','xor'];
function drawComposites(){
for (i=0;i<compositeTypes.length;i++){
var label = document.createTextNode(compositeTypes[i]);
document.getElementById('lbl'+i).appendChild(label);
var ctx = document.getElementById('can'+i).getContext('2d');
ctx.fillStyle="green";
ctx.fillRect(10,10,100,70);
ctx.globalCompositeOperation = compositeTypes[i];

62

Chapter 2
ctx.fillStyle="blue";
ctx.font="40px ComicSans";
ctx.fillText("Be Happy",20,60);
}
}

How it works...
The HTML code contains a table of four rows and three columns, thereby producing 12 cells
(0 to 11). There is a canvas and label element in each of the cells (within the <TD> tag). These
elements are captured in the JavaScript code in a loop that iterates for every composition
type. The types are mentioned in the array, and the globalCompositeOperation property
is assigned with the composite type before drawing the source.

Drawing a mouse
This recipe is an implementation of multiple functions demonstrated so far. The output looks
like this:

How to do it
The recipe is as follows.
The HTML code:
<html>
<head>
<title>Mouse</title>
<script src="mouse.js"></script>
</head>
63

Shapes and Composites


<body onload="init()">
<canvas id="MyCanvasArea" width="300" height="300" style="border:2px
solid blue;" >
your browser does not support canvas
</canvas>
<h1>A Mouse</h1>
</body>
</html>

The JavaScript code:


function init()
{
var can=document.getElementById("MyCanvasArea");
var ctx=can.getContext("2d");
drawCircle(ctx,110,60,20,6,"black","grey");
drawCircle(ctx,110,60,10,3,"pink","pink");
drawCircle(ctx,190,60,20,6,"black","grey");
drawCircle(ctx,190,60,10,3,"pink","pink");
drawTriangle(ctx,150,202.4,100,50,"black");
ctx.save();
ctx.translate(can.width/2,can.height/2);
ctx.scale(1,2);
ctx.save();
ctx.restore();
drawCircle(ctx,0,0,50,3,"black","grey");
drawCircle(ctx,-20,-20,5,3,"black","black");
drawCircle(ctx,20,-20,5,3,"black","black");
drawCircle(ctx,0,20,15,3,"black","black");
ctx.restore();
drawTriangle(ctx,151,110,12,15,"pink");
drawArc(ctx,166,122,15,90,180,false,"black","grey");
drawArc(ctx,136,122,15,0,90,false,"black","grey");
drawArc(ctx,146,138,5,-15,200,false,"white","grey");
drawArc(ctx,156,138,5,-15,200,false,"white","grey");
drawBezierCurve(ctx,192,200,210,260,220,190,240,200,"black");
}
function drawCircle(ctx,xPos, yPos, radius,borderwidth, borderColor,
fillColor){
var startAngle =
0 * (Math.PI/180);
var endAngle
= 360 * (Math.PI/180);
var radius = radius;

64

Chapter 2
ctx.strokeStyle = borderColor;
ctx.fillStyle
= fillColor;
ctx.lineWidth
= borderwidth;
ctx.beginPath();
ctx.arc(xPos, yPos, radius, startAngle, endAngle, false);
ctx.fill();
ctx.stroke();
}
function drawArc(ctx,xPos,yPos,radius,startAngle,endAngle,
anticlockwise,lineColor, fillColor){
var startAngle = startAngle * (Math.PI/180);
var endAngle
= endAngle
* (Math.PI/180);
var radius = radius;
ctx.strokeStyle = lineColor;
ctx.fillStyle
= fillColor;
ctx.lineWidth
= 2;
ctx.beginPath();
ctx.arc(xPos,yPos,radius,startAngle,endAngle,anticlockwise);
ctx.fill();
ctx.stroke();
}
function drawTriangle(ctx, x, y,Width,Height,color){
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + Width / 2, y + Height);
ctx.lineTo(x - Width / 2, y + Height);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
function drawBezierCurve(ctx,xstart,ystart,xctrl1,yctrl1,xctrl2,yctrl2
,xend,yend,color){
ctx.strokeStyle=color;
ctx.lineWidth=4;
ctx.beginPath();
ctx.moveTo(xstart,ystart);
ctx.bezierCurveTo(xctrl1,yctrl1,xctrl2,yctrl2,xend,yend);
ctx.stroke();
}

65

Shapes and Composites

How it works...
The previous recipe follows these steps:
1. The different shapes to be sent behind the larger ellipse are drawn first.
2. Then the translation and scaling is applied so that ellipses can be drawn.
3. The state is restored and then the remaining shapes are drawn above the
larger ellipse.
Observe that the coordinates used before translation and scaling differ from those used after
the effects.

66

Get more information Canvas Cookbook

Where to buy this book


You can buy Canvas Cookbook from the Packt Publishing website.
Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and most internet
book retailers.
Click here for ordering and shipping details.

www.PacktPub.com

Stay Connected:

You might also like