Skip to main content

Bezier Curves

The path element features quite a number of these commands. There are two that are relevant for our purposes:

  • Q, which instructs the path to create a quadratic Bézier curve.
  • C, which instructs the path to create a cubic Bézier curve.

Intro to Bézier Curves

Bézier curves are surprisingly common. Due to their versatility, they're a staple in most graphics software like Photoshop or Figma, but they're also used as timing functions: if you've ever used non-linear CSS transitions (like the default "ease"), you've already worked with Bézier curves!

But what are they, and how do they work?

A Bézier curve is essentially a line from a start point to an end point that is acted upon by one or more control points. A control point curves the line towards it, as if the control point was pulling it in its direction.

The following line looks like a straight line, but check out what happens when you move the points around—try dragging the middle control point up and down.

Zcx2Na

The line above is a quadratic Bézier curve; this means that it has a single control point. I'm guessing it gets its name from the fact that you can create parabola-like shapes with it:

A1pykE

A cubic Bézier curve, in contrast, has two control points. This allows for much more interesting curves:

NE3PF0

The syntax for Bézier curves in SVG path definitions is a little counter-intuitive, but it looks like this:

Live Editor
Result
Loading...

The thing that makes this counter-intuitive, to me at least, is that the startPoint is inferred in the Q command; while there are 3 points needed for a quadratic Bézier curve, only 2 points are passed as arguments to Q.

Similarly, for a cubic Bézier curve, only the control points and the end point are provided to the C command.

This syntax does mean that curves can conveniently be chained together, as one curve starts where the last one ends:

Live Editor
Result
Loading...

OK, I think that's enough playing with vanilla SVGs. Let's see how we can leverage React to make these curves dynamic!

Bézier Curves in React

Up to this point, we've been looking at static SVGs. How do we make them change, over time or based on user input?

Well, in keeping with the "meta" theme of this blog post, why not examine the draggable-with-lines Bézier curves from earlier in this post?

There's a fair bit of code to manage this, even in this slightly-simplified snippet. I've annotated it heavily, which hopefully makes things easier to parse.

Live Editor
Result
Loading...
note

The full version, with support for touch events, can be found on GitHub.

To summarize how this works:

  • React holds variables in component state for startPoint, controlPoint, and endPoint.
  • In the render method, we build the instructions for the path using these state variables.
  • When the user clicks or taps on one of the points, we update the state to keep track of which point is moving with draggingPointId.
  • As the user moves the mouse (or finger) across the SVG's surface, we do some calculations to figure out where the currently-dragging point needs to move to. This is made complex by the fact that SVGs have their own internal coordinate system (viewBox), and so we have to translate the on-screen pixels to this system.
  • Once we have the new X/Y coordinate for the active point, setState lets React know about this state change, and the component re-renders, which causes the path to be re-calculated.

References

  1. Dynamic Bézier Curves by joshwcomeau