How to Create Graphics with JavaScript Canvas

Remember when we talked about HTML and CSS, we briefly introduced something called SVG. It allows us to create vector images by simply using an XML structure.

In this lesson, we are going to discuss something similar called canvas, except it allows us to use JavaScript to create graphics on web pages. And because it uses a programming language instead of a simple markup language, that makes canvas much more flexible compared to SVG.

We know that the SVG has a DOM tree structure, and the shape, color, and position are all represented using tags and attributes.

The canvas, however, is a single node in the DOM tree. It encapsulates a space on the web page, where you can create vector images using JavaScript. This space can be defined using the <canvas> tag. Here is an example where we create a simple rectangle inside the canvas:

javascript
1<canvas width="300px" height="200px"></canvas>
javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4// Define the color of the rectangle
5context.fillStyle = "red";
6
7// The first two parameters put the top left corner of the rectangle at coordinate (10, 10)
8// The last two parameters define the width and height of the rectangle in pixels
9context.fillRect(10, 10, 100, 50);

The getContext() method is used to access the drawing interface, which is like a toolbox where your digital pens and pencils are stored. The parameter 2d stands for two-dimensional graphics.

If you are interested in creating three-dimensional graphics, you should use WebGL instead. But, we are only focusing on the 2D system for now.

Also, notice that we defined the size of the canvas at the beginning. If you don't do that, the canvas element will take a default width of 300 pixels and a height of 150 pixels.

Lines

The rectangle we just created is solid, meaning the inside of the rectangle is filled. What if we want something different?

It is also possible for us to create a rectangle that only has an outline, by using a very similar method, strokeRect(). This method also takes four parameters, the first two define the position, and the last two define the size.

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4// Define the color, position, and size
5context.strokeStyle = "blue";
6context.strokeRect(10, 10, 100, 50);
7
8// Define the width of the stroke and create a new rectangle
9context.lineWidth = 5;
10context.strokeRect(150, 10, 100, 50);

Canvas Line Rectangle

Paths

Now you might be wondering, that's not very useful, we can create rectangles using SVGs just as easily. Don't worry, the real power of the canvas starts now.

First, we need to understand what a path is. A path is a sequence of line segments.

For example, we have a line that starts from coordinate (0, 0) to (0, 50), the second line from (0, 50) to (80, 50), and the third line from (80, 50) to (80, 100). These three line segments will form a path.

The canvas allows us to do something like this:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4context.lineWidth = 5;
5context.strokeStyle = "green";
6
7context.beginPath();
8
9// The path starts at (10, 10)
10context.moveTo(10, 10);
11
12// Drawing the path: (10, 10) -> (150, 10) -> (150, 150) -> (10, 150) -> (10,10)
13context.lineTo(150, 10);
14context.lineTo(150, 150);
15context.lineTo(10, 150);
16context.lineTo(10, 10);
17
18context.stroke();

a square drawn with paths

With paths, you can create any shape you want. For example, the following code creates a triangle:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4context.beginPath();
5
6context.fillStyle = "red";
7
8context.moveTo(200, 10);
9context.lineTo(250, 100);
10context.lineTo(150, 100);
11context.lineTo(200, 10);
12
13context.fill();

canvas triangle

Curves

A path could be formed by straight lines, and it could also be formed by curves. A curve, however, is a little bit more difficult to define.

To define a curve, you need a start point, a destination point, and a control point. The curve will not go through the control point directly, but instead, it defines a point where the tangent lines of the start and destination points intersect.

the control point

For example, here is how you can define a curve:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4context.beginPath();
5
6// start point = (10, 90)
7context.moveTo(10, 90);
8
9// control point = (60,10); destination point = (90,90)
10context.quadraticCurveTo(60, 10, 90, 90);
11
12// destination point tangent
13context.lineTo(60, 10);
14
15// start point tangent
16context.moveTo(10, 90);
17context.lineTo(60, 10);
18
19context.closePath();
20context.stroke();

Curve

Sometimes, we want two separate control points for the start and destination.

Curves with two control points

That is also possible to achieve using the bezierCurveTo() method.

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4context.beginPath();
5
6// start point = (10, 90)
7context.moveTo(10, 90);
8
9// start control point = (60,10); destination control point = (30,80); destination point = (90,90)
10context.bezierCurveTo(60, 10, 30, 80, 90, 90);
11
12// destination point tangent
13context.lineTo(30, 80);
14
15// start point tangent
16context.moveTo(10, 90);
17context.lineTo(60, 10);
18
19context.closePath();
20context.stroke();

Curve with two control point

Texts

Texts might also be useful when creating graphs. You can draw texts using either fillText and strokeText. The latter will only render the outline of the texts instead of filling it.

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4context.font = "28px Georgia";
5
6context.fillText(
7  "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
8  10,
9  50
10);
11
12context.strokeText(
13  "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
14  10,
15  100
16);

Texts in Canvas

The last two parameters indicate the position of the text, but unlike drawing shapes, they define the coordinate of the beginning of the text baseline, which is the line that the text "stands" on.

Transformations

There are primarily three types of transformations, translate(), scale(), and rotate(). They are very similar to the transformation functions we discussed for CSS.

Remember that these methods need to be put before the graph you wish to transform.

translation() will move the graph from one position to another:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4// Move whatever graph created after to the right for 50px and downward for 100px
5context.translate(50, 100);
6
7// Create a graph
8context.beginPath();
9
10context.fillStyle = "red";
11
12context.moveTo(200, 10);
13context.lineTo(250, 100);
14context.lineTo(150, 100);
15context.lineTo(200, 10);
16
17context.fill();

The scale() will make the original graph bigger or smaller:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4// Make the graph two times wider (along the x-axis) 0.5 times shorter (along the y-axis)
5context.scale(2, 1 / 2);
6
7// Create a graph
8// . . .

And finally, rotate() can rotate the graph along an axis:

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4// Rotate the graph clockwise for 18 degrees. Notice that the rotate() method uses radians instead of degrees.
5context.rotate(0.1 * Math.PI);
6
7// Create a graph
8// . . .

Inserting bitmap images

In computer graphics, there are something called vector graphics and bitmap graphics. All the graphs we've been talking about so far are vector graphics.

Their primary difference is that the bitmap graphics are formed by pixels while the vector graphics are not. Instead, they are formed by paths, with a direction and a magnitude (length), like a vector.

However, sometimes, it is necessary for us to insert some bitmap graphics in our vector design. You can do that by using the drawImage() method.

javascript
1let canvas = document.querySelector("canvas");
2let context = canvas.getContext("2d");
3
4let img = document.createElement("img");
5img.src = "cat.jpg";
6
7img.addEventListener("load", () => {
8  context.drawImage(img, 10, 10, 360, 240);
9});

In this example, the image will be drawn at the coordinate (10, 10), with the size 360*240px.

We need to add the event listener because, without it, the image will load after the canvas, so we have to make the canvas wait for the image to load first.