# HTML5 Canvas: Paths

Jakob Jenkov |

A HTML5 Canvas path is a series of points with drawing instructions between those points. For instance, a series of points with lines between them, or with arcs between them.

Paths are used to draw many types of shapes (lines, circles, polygons etc.) on an HTML5 canvas, so it is important to understand this central concept.

## Beginning and Closing a Path

A path is started and ended using the 2D Context functions `beginPath()`

and `closePath()`

,
like this:

var canvas = document.getElementById("ex1"); var context = canvas.getContext("2d");context.beginPath();//... path drawing operationscontext.closePath();

## moveTo()

When drawing using a path, you are using a virtual "pen" or "pointer". This virtual pointer
is always located at some point. Moving the virtual pointer is done using the 2D Context function
`moveTo(x, y)`

, like this:

context.moveTo(10,10);

This example moves the pointer to the point 10, 10.

## lineTo()

The `lineTo()`

function draws a line from the location of the virtual pointer to the point
passed as parameter to the `lineTo()`

function. Here is an example:

context.beginPath(); context.moveTo(10,10); context.lineTo(50,50); context.closePath();

This example moves the pointer to the point 10,10 and then draws a line from that point to the point 50, 50.

`lineTo()`

also moves the virtual pointer to the end point of the line. Thus, in the example
above the pointer is moved to 50,50 , while instructing the canvas to draw a line to that point.

## stroke() + fill()

Nothing of a path is actually drawn until you instruct the 2D Context to draw the path.
This is done by calling either `stroke()`

or `fill()`

on the 2D Context.

The `stroke()`

function will draw the outline of the shape defined by the path operations.

The `fill()`

function will fill out the shape defined by the path operations.

Here are an example of both `stroke()`

and `fill()`

applied to identical shapes:

context.beginPath(); context.moveTo(10,10); context.lineTo(60,50); context.lineTo(110,50); context.lineTo(10,10);context.stroke();context.closePath(); context.beginPath(); context.moveTo(100,10); context.lineTo(150,50); context.lineTo(200,50); context.lineTo(100,10);context.fill();context.closePath();

Here is the result of the above code:

## Line Width

You can set the width of the line drawn by the various stroke functions using the `lineWidth`

property of the 2D Context. Here is an example:

context.lineWidth = 10;

The example above sets the line width to 10 pixels for all subsequent stroke drawing operations.

Here are three lines drawn with a line width of 1, 5 and 10:

With line widths larger than 1 the extra width of the line is drawn outside the center line. That is, if you draw a line from 10,10 to 100,10 with a line width of 10, the line will actually start already at 10,5 and extend through 10,15, and horizontally to 100,5 and 100,15 from there. Like a rectangle.

## Line Cap

When drawing lines using a path you can set the lines line cap. The line cap defines how the end of the line is drawn.

The line cap is set via the `lineCap`

property of the 2D Context. It can take these
values:

- butt
- round
- square

The value `butt`

results in a line end that is flat and orthogonal to the line.

The value `round`

results in a rounded line end, with a radius of the rounding that
is equal to half the width of the line.

The value `square`

results in a rectangle being drawn at the end of the line. The
rectangle has the size of ` line width x line width / 2`

.

Here are a set of examples illustrating the line caps. All lines are drawn with a line width
of 10. The left most lines uses the `lineCap`

value `butt`

. The middle
lines uses the `lineCap`

value `round`

. The rightmost lines uses the
`lineCap`

value `square`

.

It can be a bit difficult to see the difference between lines drawn with a `lineCap`

value of `butt`

and `square`

. Therefore I have created a few examples of
line pairs using `butt`

and `square`

, drawn close to each other so you can
see the difference. The top or left line is using `butt`

, and the bottom or right line
is using `square`

.

As you can see, the lines using a `lineCap`

value of `square`

have an extra rectangle
drawn at the end, which makes the line a little longer.

## Line Join

The `lineJoin`

property of the 2D Context defines how the point is drawn where two lines are connected.
The point where two lines are connected is called the "line join". The `lineJoin`

property can have
the following values:

- miter
- bevel
- round

Here are three code examples setting the line join:

context.lineJoin = "miter"; context.lineJoin = "bevel"; context.lineJoin = "round";

A value of `miter`

results in a triangular corner being drawn for the line join.

A value of `bevel`

results in a flat (linear) corner being drawn for the line join.

A value of `round`

results in a round corner being drawn for the line join.

Here are three examples showing (from the left) `miter`

, `bevel`

and `round`

used as value for the `lineJoin`

property.

## arc()

The 2D Context function `arc()`

draws an arc on the canvas.

The `arc()`

function takes 6 parameters:

**x**: x coordinate of center point of arc.**y**: y coordinate of center point of arc.**radius**: radius of arc.**startAngle**: angle in radians from which the arc starts.**endAngle**: angle in radians at which the arc ends.**anticlockwise**: sets whether the direction to draw in is anticlockwise or not (not = clockwise).

Here is a code example:

context.lineWidth = 3; var x = 50; var y = 50; var radius = 25; var startAngle = (Math.PI / 180) * 45; var endAngle = (Math.PI / 180) * 90; var anticlockwise = false; context.beginPath(); context.arc(x, y, radius, startAngle, endAngle, anticlockwise); context.stroke(); context.closePath();

This code example draws an arc with center point at 50, 50 with a radius of 25 pixels, starting from 45 degrees and continuing until 180 degrees. The degrees going from 0 to 360 are converted to radians, as you may have noticed.

Here is how the code example looks when drawn on a canvas:

Here is the same code sample, but with `anticlockwise`

set to `true`

:

To draw a full circle, simple set `startAngle`

to `0`

and
`endAngle`

to

`2 * Math.PI`

which is equal to `(Math.PI / 180) * 360`

.

## arcTo()

The 2D Context has an `arcTo()`

function, but its abilities can be mimicked
using `lineTo()`

and `arc()`

, so I will skip over it.

## quadraticCurveTo()

The `quadraticCurveTo()`

function draws a quadratic Bezier curve from one
point to another. The curve is controlled by a single control point.
Here is a code example:

context.lineWidth = 3; var fromX = 50; var fromY = 50; var toX = 100; var toY = 50; var cpX = 75; var cpY = 100; context.beginPath(); context.moveTo(fromX, fromY); context.quadraticCurveTo(cpX, cpY, toX, toY); context.stroke(); context.closePath();

This code example draws a curve from 50, 50 to 100, 50 using the control point 75, 100 (cpX, cpY). The resulting curve looks like this:

The little dot on the canvas is the control point which I have drawn there. It is not part of the curve normally.

## bezierCurveTo()

The `bezierCurveTo()`

function draws a cubic Bezier curve from one point another.
A cubic Bezier curve has 2 control points, whereas the quadratic Bezier curve only has 1 control point.
Here is a code example:

context.lineWidth = 3; var fromX = 50; var fromY = 50; var toX = 300; var toY = 50; var cp1X = 100; var cp1Y = 100; var cp2X = 250; var cp2Y = 100; context.beginPath(); context.moveTo(fromX, fromY); context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY); context.stroke(); context.closePath();

This code example draws a curve from 50, 50 to 300, 50 using the control points 100, 100 (cp1X, cp1Y) and 250, 100 (cp2X, cp2Y). The resulting curve looks like this:

The two little dots on the canvas are the control points that I have drawn to show you where they are. They are not drawn as part of the curve.

Here is a different example using different start point, end point and control point:

context.lineWidth = 3; var fromX = 50; var fromY = 50; var toX = 300; var toY = 50; var cp1X = 100; var cp1Y = 10; var cp2X = 250; var cp2Y = 100; context.beginPath(); context.moveTo(fromX, fromY); context.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, toX, toY); context.stroke(); context.closePath();

Here is the corresponding curve:

Again, the two little dots are the control points that I have rendered explicitly.

Tweet | |

Jakob Jenkov |