The HTML 5 canvas API allows you to draw bézier curves and quadratic curves out of the box. The API is easy to use, and the curves come out beautifully. But what if you wanted to draw something else at the halfway point of a curve? You’d have to know the coordinates of a point on the curve to be able to do so. And, if you wanted to draw an arrowhead halfway down the curve in the direction of the curve, you’d have to know the coordinates as well as the angle of the curve at that point.

In this tutorial, we’ll show you simple code that allows you to calculate the coordinate and angle of any point on a HTML 5 canvas bézier or quadratic curve.

Drawing a curve

The HTML 5 API has a method for drawing bézier curves:

ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

The parameters are:

  • cp1x: The x axis of the coordinate for the first control point.
  • cp1y: The y axis of the coordinate for the first control point.
  • cp2x: The x axis of the coordinate for the second control point.
  • cp2y: The y axis of the coordinate for the second control point.
  • x: The x axis of the coordinate for the end point.
  • y: The y axis of the coordinate for the end point.

A snippet (from MDN) shows how to draw a curve. The control points are red, while the start and end points are blue.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.moveTo(50,20);
ctx.bezierCurveTo(230, 30, 150, 60, 50, 100);
ctx.stroke();

ctx.fillStyle = 'blue';
// start point
ctx.fillRect(50, 20, 10, 10);
// end point
ctx.fillRect(50, 100, 10, 10);

ctx.fillStyle = 'red';
// control point one
ctx.fillRect(230, 30, 10, 10);
// control point two
ctx.fillRect(150, 60, 10, 10);

See the pen on CodePen.

Clearly, the API allows you to provide end point coordinates and control points, but no way to access intermediate coordinates.

How are bezier curves really drawn?

Bézier curves obey a mathematical formula that you can look up on Wikipedia. You’ll find various formulas there; the one we’re interested in is the cubic bézier curve:

Cubic bézier curve formula

This formula allows you to draw your own bézier curves (though you won’t have to, because HTML 5 canvas already takes care of that) as well as calculate the (x,y) coordinates of any point along the curve.

The various P symbols in the formula are (x,y) coordinate pairs with the following meaning:

  • P0: Start coordinate pair
  • P1: Control point 1
  • P2: Control point 2
  • P3: End coordinate pair

The t symbol, meanwhile, goes from 0 to 1 and determines how far we are along the curve. For t=0, B will be the start coordinate, for t=1, B will be the end coordinate, and for t=0.5, B will be the coordinate exactly halfway the curve.

Calculating coordinates along a cubic bézier curve in JavaScript

All we have to do is transcribe the Bézier formula to JavaScript.

function getBezierXY(t, sx, sy, cp1x, cp1y, cp2x, cp2y, ex, ey) {
  return {[
    x: Math.pow(1-t,3) * sx + 3 * t * Math.pow(1 - t, 2) * cp1x 
      + 3 * t * t * (1 - t) * cp2x + t * t * t * ex,
    y: Math.pow(1-t,3) * sy + 3 * t * Math.pow(1 - t, 2) * cp1y 
      + 3 * t * t * (1 - t) * cp2y + t * t * t * ey
  };
}

Now, if we provide a start coordinate sx, sy, an end coordinate ex, ey, control points and a value of t between 0 and 1, we’ll get the (x,y) coordinate of the point on the curve at t:

var coord = getBezierXY(0.5, 0, 0, 60, 80, 40, 20, 100, 100);

Calculating coordinates along a quadratic bézier curve

The HTML 5 canvas API also support quadratic bézier curves. These are actually simpler than cubic bézier curves and only use one control point. They, too, have a formula:

Quadratic bézier curve formula

The various P symbols in the formula are (x,y) coordinate pairs with the following meaning:

  • P0: Start coordinate pair
  • P1: Control point
  • P2: End coordinate pair

And, again, we can convert this to a JavaScript function:

function getQuadraticXY(t, sx, sy, cp1x, cp1y, ex, ey) {
  return {
    x: (1-t) * (1-t) * sx + 2 * (1-t) * t * cp1x + t * t * ex,
    y: (1-t) * (1-t) * sy + 2 * (1-t) * t * cp1y + t * t * ey
  };
}

Now, if we provide a start coordinate sx, sy, an end coordinate ex, ey, a control point and a value of t between 0 and 1, we’ll get the (x,y) coordinate of the point on the curve at t:

var coord = getQuadraticXY(0.5, 0, 0, 60, 80, 100, 100);

Calculating the curve angle anywhere along a cubic bézier curve

You may have a use case where you need to find the angle that a bézier curve makes with the x-axis at some point. Maybe you’d like to draw an arrowhead at a point along the curve, neatly pointing in the direction of the curve.

The angle of a cubic bézier curve at any point is determined by calculating the derivative of the cubic bézier curve formula, which looks like this:

Cubic bézier curve formula derivative

We can convert this to a JavaScript function:

function getBezierAngle(t, sx, sy, cp1x, cp1y, cp2x, cp2y, ex, ey) {
  var dx = Math.pow(1-t, 2)*(cp1x-sx) + 2*t*(1-t)*(cp2x-cp1x) + t * t * (ex - cp2x);
  var dy = Math.pow(1-t, 2)*(cp1y-sy) + 2*t*(1-t)*(cp2y-cp1y) + t * t * (ey - cp2y);
  return -Math.atan2(dx, dy) + 0.5*Math.PI;
}

… and this will give us the angle (in radians) between the bézier curve and the horizontal x-axis at point t.

We can put this to use and draw an arrowhead at 20% along the bézier curve, which neatly follows the angle of the curve at that point:

See the pen on CodePen.

Calculating the curve angle anywhere along a quadratic bézier curve

Of course, we can do the same thing for a quadratic bézier curve. The derivative of the quadratic bézier curve formula looks like this:

Quadratic bézier curve formula derivative

And converted to a JavaScript formula:

function getQuadraticAngle(t, sx, sy, cp1x, cp1y, ex, ey) {
  var dx = 2*(1-t)*(cp1x-sx) + 2*t*(ex-cp1x);
  var dy = 2*(1-t)*(cp1y-sy) + 2*t*(ey-cp1y);
  return -Math.atan2(dx, dy) + 0.5*Math.PI;
}

Happy coding!