DEV Community

Jess
Jess

Posted on

Getting Started with the Canvas API: Complex Shapes

In Part 1 of Getting Started with the Canvas API I went over the basics of creating lines and rectangles. Here I'm going to discuss creating more complex shapes.

First, I'm going to create a 300x300 canvas element and get a reference to it in JavaScript.

<canvas id="canvas" height="300" width="300"></canvas>
Enter fullscreen mode Exit fullscreen mode
const ctx = document.getElementById('canvas').getContext('2d');
Enter fullscreen mode Exit fullscreen mode

Connecting Lines

As I explained in Part I, you can create lines by beginning a path (using beginPath()), plotting the x,y values of the beginning and end of your line using the moveTo() and lineTo() methods, and creating the line stroke(). You can actually continue plotting points for your line before creating the stroke.

When lineTo() is used, it creates an x,y end point for the line. When it is used again along the same path, the line extends from the previous end point.

ctx.lineWidth = 3; // just making it a little more visible
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(20,100);
ctx.lineTo(100,100);
ctx.lineTo(20,200);
ctx.lineTo(100,200);
ctx.lineTo(200, 20);
ctx.lineTo(200, 200);
ctx.stroke();
Enter fullscreen mode Exit fullscreen mode
A line zig-zagging in different directions

Triangles

In order to create a closed shape, you can create a lineTo() back to the starting point.

ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(ctx.canvas.width/2, 20);
ctx.lineTo(20, ctx.canvas.height - 20);
ctx.lineTo(ctx.canvas.width - 20, ctx.canvas.height - 20);
ctx.lineTo(ctx.canvas.width/2,20);
ctx.stroke();
Enter fullscreen mode Exit fullscreen mode
outline of a triangle with a disjointed connection

But ew, what's going on here?

An outline of a triangle with the top disjointed connection circled

You can fix this by changing the fillCap of your line, but then it doesn't quite match the other pivot points.

ctx.fillCap = 'round';
Enter fullscreen mode Exit fullscreen mode
An outline of a triangle with the top connection rounded

Instead of changing the fillCap, here's a better option:

Use closePath() in place of the final lineTo() point connection and it will automatically connect those points neatly.

ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(ctx.canvas.width/2, 20);
ctx.lineTo(20, ctx.canvas.height - 20);
ctx.lineTo(ctx.canvas.width - 20, ctx.canvas.height - 20);
ctx.closePath(); // <--- replaced the final lineTo with closePath
ctx.stroke();
Enter fullscreen mode Exit fullscreen mode
An outline of a triangle with each segment connection point matching

Line Joins

There are also lineJoin options to style your segment connections: bevel, miter, and round. round rounds off the corners, miter joins the outside edges of the line segments to a single point and is the default, and bevel fills the endpoint of the connected line segments and flattens it off.

A red filled triangle with black outline

Filling Shapes

You can fill in the shape by using fillStyle and fill().

ctx.fillStyle = 'red'; < --- set the color
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(ctx.canvas.width/2, 20);
ctx.lineTo(20, ctx.canvas.height - 20);
ctx.lineTo(ctx.canvas.width - 20, ctx.canvas.height - 20);
ctx.fill(); < --- fill the shape
ctx.closePath();
ctx.stroke();
Enter fullscreen mode Exit fullscreen mode
A red filled triangle with black outline

Order matters here. If you fill() after stroke(), the outline will appear thinner because the fill is on top.

ctx.fillStyle = 'red';
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(ctx.canvas.width/2, 20);
ctx.lineTo(20, ctx.canvas.height - 20);
ctx.lineTo(ctx.canvas.width - 20, ctx.canvas.height - 20);
ctx.closePath();
ctx.stroke();
ctx.fill(); < --- fill the shape after creating the stroke

Enter fullscreen mode Exit fullscreen mode
A red filled triangle with black outline

Top comments (3)

Collapse
 
yellow1912 profile image
yellow1912 • Edited

Thank you. In the next part can you show how to create soft curve lines that connect objects (as we often see in graphs like this intercom.com/series?on_pageview_ev...

I actually want to create something similar but not sure where to start.

Collapse
 
robotspacefish profile image
Jess

You mean like how a line connects to a circle or arrowhead? My next post will probably be on circles and curved lines so hopefully it'll be what you're looking for. I'll see if I can whip up an example that will help you get started!

Collapse
 
yellow1912 profile image
yellow1912

Thank you very much. I'm interested in those curved lines and how we should support redrawing those lines kinda dynamically when we drag elements around.