Go to top

# Draw Smooth Line through points with HTML5 Canvas

, 26 Aug 2013
 Rate this:

Note: Version 2 and onward is maintained at Github.

## Introduction

Canvas comes with a few functions to draw smooth lines such as Bezier-curves. However, sometimes we just need to draw smooth lines between and through a few points without worrying about control points, or calculating pseudo control points by means of trigonometric approaches.

Here is a simple function that allows you to feed it a simple array of X and Y coordinates and it will draw smooth lines (cardinal spline) between them.

## Using the Code

Obvious first step: reference the file in your HTML code or merge it with the existing JavaScript code. The usage is straight forward. Define a simple array with X and Y coordinates in succession.

Then call the function with the canvas context and array as argument. Optionally, you can set a tension value between `0 `and `1 `(if none is given, it uses the default `0.5`).

```var myPoints = [1,2, 10,20, 30,40 ]; //here 3 points: x1,y2, x2,y2, x3,y3

drawCurve(ctx, myPoints);```

The function comes with a set of options which may or may not be useful - the full function looks like this:

`drawCurve(context, points, [tension], [isClosed], [numOfSegments], [showPoints])  `
• `context` - the canvas' 2D context which you allocate yourself from the canvas element.
• `points `- the array of points, minimum two points. The array is cloned internally as it needs to duplicate the start and end points which otherwise would alter the input array (feel free to modify if you need to squeeze a few more milliseconds out of it).
• `tension `- (optional) typically a value between `0 `- `1`, default value is `0.5`.
• `isClosed `- (optional) if you want a closed loop. Default is open curve. Please note that in the current version, one junction point will not be smoothed (haven't wrapped my head around this one - suggestions are welcome!). NOTE: From version 1.3 this option is obsolete as I have found no solution to this problem yet. The argument is still present but nothing will happen using it.
• `numOfSegments `- (optional) segments between each set of points, or the line resolution if you like. Defaults to 16. Good initial range is between 10-16, 20-25 for long curves/lines.
• `showPoints `- (optional) draw a small square where each actual points are. Mainly for debugging purposes. Default is `false`.

From version 1,1, the main function is split into three functions: the `drawCurve()` works as before. Use the `getCurvePoints()` to get an array with points for a smoothed line based on the input points, Use `drawLines() `to draw any array with x,y points.

`getCurvePoints(points, tension, isClosed, numberOfSegments)   `

As you can see, it follows the same pattern as the `drawCurve()` with the exception of `context `and `showPoints`. This function can therefore be useful outside a canvas context as well. All the math is now in this function and is used internally by `drawCurve(`).

The third function is the simple `drawLines() `function which takes an array of points and draws lines between them:

`drawLines(context, points) `
• `context` - the canvas' 2D context which you allocate yourself from the canvas element.
• `points `- the array of points, minimum two points. This can be any array of points in the arrangement x1,y1,x2,y2,...xn,yn.

This change allows you to easily convert a point array into an array consisting of points for a smooth curve without rendering anything, which of course can be used for anything including merging lines.

## Extending the Canvas (Optional)

You can easily extend the canvas context if you prefer to call the `drawCurve` on the context object instead.

In order to extend it, add these few lines to the JavaScript (included from version 1.3):

```if (CanvasRenderingContext2D != 'undefined') {
CanvasRenderingContext2D.prototype.drawCurve =
function(pts, tension, isClosed, numOfSegments, showPoints) {
drawCurve(this, pts, tension, isClosed, numOfSegments, showPoints)}
} ```

Now you can call the function like this instead.

`context.drawCurve(myPoints);`

## Under the Hood

This is a "native" function in the sense that all point and line calculations are done within the function and not by using other canvas curve functions such as the Bezier curves.

The function segments the distance between two points. For each segment, it uses the points plus one point before and one after to calculate the cardinal points used for interpolation.

The number of segments determines the "resolution" of the curve. The less segments there are, the more crude the curve, and of course, the more the merrier. However, this is useful only up to a certain point where we won't be able see much difference in smoothness. From experience, a value between 10 and 16 segments is a good starting point for typical uses. If you have great distance between two points, then you will probably need more segments as the number of segments are the same for all lines no matter length.

The tension value determines how "round" the connection between the lines will be drawn. In essence, a value of zero is the same as drawing straight lines between the points. A value of 1 will draw them very rounded. Typically a value of 0.5 is most usable as this gives a smooth curve without exaggerated curves.

You can always go outside the 0-1 interval to get curly junctions.

The smoothed lines are guaranteed to go through the actual points.

## Demo

The archive attached to the tip comes with a demo page which allows you to play around with different segment and tension values.

There are two versions of the function included, one developer version and one minimized version for production use. There are no dependencies other than that it obviously requires a HTML5 canvas (you can use excanvas with IE8 or lower versions) and JavaScript enabled.

## History

#### Version 1.3

• More optimizations for even higher speeds
• Corrected mangled power calculations as a result of former optimization (1.2)
• Removed support for closed curves (for now) - no change in order of arguments

#### Version 1.2

• Highly optimized code for even faster rendering
• Additional file that extends `Canvas `to have `context.curve(points, tension, segments)` The extension version comes in an even more optimized state due to be all inline

#### Version 1.1

• Split main function into three functions which offer more versatility
• A couple of performance optimizations (both demo and function)

## Share

United States
Binary since 1982 from the age of the Vics, guru meditations and 01000100k asm, to .Net and web apps.

## You may also be interested in...

### How to Do a Big Data Project

 View All Threads First Prev Next
 Not an article Karthik Harve 14-Mar-13 21:31
 Message Removed Abdias Software 14-Mar-13 23:13
 Re: Not an article Karthik Harve 14-Mar-13 23:20
 Re: Not an article SoMad 15-Mar-13 18:34
 Re: Not an article [modified] Abdias Software 16-Mar-13 10:15
 Last Visit: 31-Dec-99 18:00     Last Update: 20-Sep-14 18:29 Refresh 1