Drawing Shapes on HTML Canvas — Arcs and Rectangles

John Au-Yeung - Jan 30 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

The HTML canvas element lets us draw shapes and do various things with them. The most basic things include adding shapes, changing their color, and drawing paths.

In this article, we’ll look at how to draw shapes on the canvas, including arcs and rectangles

The Grid

Everything on the canvas is located on a grid. The items are positioned by coordinates. The top left corner is the origin (0, 0) and everything is placed relative to that. Normally 1 unit in the grid is 1 pixel on the screen.

The x-coordinate is larger as we move to the right and the y-coordinate increases as we go down.

Drawing Rectangles

Canvas supports only 2 primitive shapes — the rectangle and paths.

We can draw rectangles by using the fillRect method of the rendering context. It takes 4 arguments, which are the x and y coordinates of the top left corner respectively, and the width and height of the rectangle. The rectangle will be filled with a color.

The strokeRect method takes the same arguments as the fillRect method and let us draw a rectangular outline.

Finally, there’s the clearRect method, which clears the specified rectangular area, making it fully transparent. It takes the same arguments as the other 2 methods.

For example, we can use these methods as follows:

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.fillRect(5, 5, 80, 80);
ctx.clearRect(15, 15, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
Enter fullscreen mode Exit fullscreen mode

given that we have the following HTML:

<canvas>

</canvas>
Enter fullscreen mode Exit fullscreen mode

and CSS:

canvas {
  width: 200px;
  height: 200px;
  border: 1px solid black;
}
Enter fullscreen mode Exit fullscreen mode

The fillRect draws a rectangle with the black background, which has a clear rectangle drawn with the clearRect method over it on the top left. The black rectangle has the top-left corner in (5, 5) and is 80x80 pixels large.

The clear rectangle has its top-left corner on (15, 15) and it’s 60x60 pixels large.

Then we have the rectangle drawn with the strokeRect method farther to the bottom right. Its top-left corner is at (50, 50) and it’s 50x50 pixels large.

In the end, we have the following result:

Drawing Paths

In addition to rectangles, we can draw paths, which are line segments that are connected together. It can be a different shape or color. The path can be closed.

We create paths with the following steps:

  1. We create the path
  2. Use drawing commands to draw into the path
  3. Then we can stroke or fill the path to render it.

There’re a few methods we need to call for drawing paths. We need to call the beginPath method to create a new path. Future drawing commands will be directed into the path and build it up.

Then we use 3 other methods to draw the path. We have the closePath method to add a straight line to the path, going to the start of the current subpath.

We use the stroke method to draw the shape by stroking its outline. Then we can use the fill method to fill the path’s content area if we wish.

We move to the coordinates of the screen with the moveTo method, which takes the x and y coordinates to move to as arguments. Then we can draw a line from that coordinate to another with the lineTo method, which takes the x and y coordinates to draw the line from wherever the current coordinate is.

For example, we can draw a triangle by writing:

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(100, 50);
ctx.lineTo(50, 100);
ctx.lineTo(150, 100);
ctx.fill();
Enter fullscreen mode Exit fullscreen mode

We first start trying at (100, 50). Then we draw a line from (100, 50) to (50, 100) with the first lineTo call. Then we draw from (50, 100) to (150, 100) again with the lineTo method. Finally, we called fill to draw the shape by filling in the path’s content area.

In the end, we get:

moveTo Method and Arcs

The moveTo method is handy for moving the originating point of the drawing path without drawing anything.

It takes the x and y coordinates that we want to move to.

We can write:

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(125, 75);
ctx.arc(75, 75, 50, 0, 2 * Math.PI);
ctx.moveTo(135, 75);
ctx.arc(75, 75, 60, 0, 2 * Math.PI);
ctx.stroke();
Enter fullscreen mode Exit fullscreen mode

To draw a circle, we move to the rightmost point of the circle with the moveTo method. Then we call the arc method to draw the arc. The first 2 arguments are the x and y coordinates of the center. The third argument is the radius, the 4th argument is the starting angle and the last argument if the ending angle. 

In the code above, the starting angle is the 3 o’clock position. Clockwise or counterclockwise directions are relative to this point.

We can also pass in an additional boolean argument to specify if we want to draw counterclockwise.

In addition. There’s the arcTo method which takes the x and y coordinates of the starting point and the ending point respectively for the first 4 arguments. The 5th argument has the radius of the arc.

After writing that code, we get the following circles.

ctx.moveTo(125, 75);
ctx.arc(75, 75, 50, 0, 2 * Math.PI);
Enter fullscreen mode Exit fullscreen mode

draws the smaller circle with a radius of 50 pixels, and:

ctx.moveTo(135, 75);
ctx.arc(75, 75, 60, 0, 2 * Math.PI);
Enter fullscreen mode Exit fullscreen mode

draws the bigger circle with a radius of 60 pixels.

With the canvas element, we can draw shapes easily. There’re methods specifically for drawing rectangles. For curved shapes and lines, we can draw them with the arc and arcTo methods. 

Shapes can be drawn filled or not depending on our preferences.

We can use the moveTo method to move to a given coordinate without drawing anything.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .