Drawing Paths - Curves and Arcs

Keith Peters
InstructorKeith Peters
Share this video with your friends

Social Share Links

Send Tweet
Published 9 years ago
Updated 5 years ago

When drawing on your HTML canvas in JavaScript, you aren't restricted to straight lines. Using curves and arcs you are able to create smooth curved lines.

As I said earlier, with enough short, straight line segments, you can pretty much draw any shape imaginable. For instance, here, I'll draw a sine wave. I'll begin a path and move the cursor to (0, 300). Then I'll execute a for loop starting the variable x at one and incrementing it up to 600.

In the loop, I'll calculate y as 300, which is the midpoint of the height of the canvas, plus the sine of x times 300. Math.sin will return a number from -1 to +1 and when multiplied by 300 and added to 300, will give you numbers ranging from 0 to 600. Then I'll say, "lineTo(x, y)" and once the for loop is done, stroke the path.

There's a sine wave, but the wave length is a bit too high. If we multiply x by something like 0.01, we'll get a smoother wave. This is upside down because the y-axis in Canvas is reversed from usual Cartesian coordinates, but the important thing to notice is that although this shape is rendered from 600 individual straight lines, it appears to be a nice, smooth curve.

While you could render virtually any curve with line segments, as you can see, it's not the most concise code in the world. Fortunately, Canvas' drawing API comes with a few curve-drawing functions. The first is quadraticCurveTo. This will draw a curve starting at the current cursor position, towards a control (x, y) point and ending at a final (x, y) point. Note that the curve will not go through the control point. It will only go towards it and be controlled by its position.

The other curve function is bezierCurveTo, which works the same way but has two control points. This is the exact kind of curve you're used to seeing in any drawing programs that offer a Bézier curve tool. The control points are used to shape the resulting curve.

To demonstrate a quadratic curve, I'll create three point objects and give each one a random x and y. Then I'll call beginPath, move to p0's x and y, then call CurveTo, passing in p1 and p2's x's and y's. This makes p1 the control point and p2 the endpoint. Finally, I'll call context.stroke. You can see that the curve is created.

To make things a bit clearer, I'll create another function called "drawPoint." This will call fillRect to draw a small square centered around each point. Then I'll call drawPoint, passing in p0, p1, and p2. Now you can see the three points and how they create the curve. Rerunning the script a few times gives you more random points and different curves.

We can use the same code to demonstrate bezierCurveTo. I'll create a p3 and call the Bézier function, adding p3 x and y and finally calling drawPoint with p3. You should be able to see how the two control points can create a more complex curve than the single control point in the quadratic curve.

The final type of built-in curve is an arc. The arc function can be used to draw circles or a portion of a circle. Oddly enough, there is no straight-up circle function, but you can get by with arc. The parameters of arc start with the x and y position of the center of the circle and its radius. Those are pretty straightforward. Next come the start and end angles of the arc. These are in terms of radians, as are most angle measurements in JavaScript. A radian is equal to roughly 57 degrees, and 360 degrees is equal to two pi radians.

To draw a circle, you would begin a path, then call arc with the center (x, y) and radius. Setting the start angle to zero and the end angle to Math.PI times two. Finish it up with a stroke. There's your circle. If you want to draw an arc, specify a different start or end angle. Here, I'll change the angle to two radians. This starts the circle at zero, or due right, and ends it at about 114 degrees, going around clockwise.

What if you wanted it to be drawn in the other direction? There's a final, optional parameter called "anti-clockwise," or "counterclockwise," if you prefer. This defaults to false, causing the arc to be drawn clockwise, but if we change that to true, you can see that the arc is drawn in the opposite direction.

There's also an arcTo function, but the way it's spec'd out is quite difficult to understand. Several browser manufacturers have actually gotten it completely wrong. I'm going to mention it. If you want to do a bit more research on it and figure it out, you can. Here's a link that should help.

~ 9 years ago

For some reason; I was unable to get the canvas to look correctly on my retina screen without specifying the width, height attributes along with explicitly specifying the uniques in CSS as well--a convention I'm usually used to with my past experiences with Canvas.

I then do the following to get a non-cropped result: w/ Chrome and Safari:

  if('devicePixelRatio' in window &&
context.webkitBackingStorePixelRatio < 2) {
canvas.setAttribute('width', 600 * devicePixelRatio)
canvas.setAttribute('height', 600 * devicePixelRatio)
~ 6 years ago


Markdown supported.
Become a member to join the discussionEnroll Today