Getting to know the <path>
July 22, 2018
If you haven’t already checked out my first post in this series, then you may wish to read that first, as that covers the basics of SVG. This article attempts to dive into some of the more advanced parts of the SVG spec.
Once we understand the viewbox
and know how to add some simple shapes to our graphics,
we can then look to some of the more advanced tags in SVG to really get cooking. In this article,
I will introduce you to the all-powerful path
tag, which
will give us the ability to draw shapes of any complexity.
Allow me to introduce perhaps the most important tag in SVG, the <path>
tag.
Once we know the <path>
tag, we could decide to forget all about
the other shape and line tags — as the <path>
tag can recreate
all of them.
But before we start erasing <circle>
and <line>
from our memory,
Eternal Sunshine of the Spotless Mind-style, it should be noted that the syntax for creating
a path is a little more difficult to master, especially if we want to do more complicated shapes.
The <path> to enlightenment
The <path>
tag has only one attribute to understand, the definition attribute (d
),
but this attribute expects a particular syntax for defining all the information about the path.
Here’s a very simple example of a <path>
, to get us started:
<svg viewBox="0 0 10 10">
<path d="M 0,0 H 10 V 10 Z" />
</svg>
The d
attribute takes a series of letters and numbers, which plot the path onto our SVG viewbox.
Each letter signals the beginning of a letter command, and the numbers following that letter
are the values which that command uses to create the next part of the path.
Letter commands are case-sensitive — an upper-case command (eg.
M
) specifies its arguments as absolute positions, while a lower-case command (eg.m
) specified points relative to the current position.
Let’s break down this example, command by command, to see what commands we have available to us, and what each does:
Move to (M x y
)
Used to move the path to a point, without drawing any sort of line between this and the previous point. Often thought of like picking up a pen and putting it down on the point to begin/continue drawing.
It is good practice to begin every path with the M
command.
Line to (L x y
)
Draws a straight line from the previous point to the x
and y
coordinates specified.
Vertical line (V y
)
Draws a straight line up or down from the previous point to the x
coordinate specified (y
remains unchanged).
Horizontal line (H x
)
Draws a straight line left or right from the previous point to the y
coordinate specified (x
remains unchanged).
Close path (Z
)
Closes the current subpath by connecting the last coordinates with the first (If the two points are not the same, a straight line is drawn between them).
Okay, so that was a lot of work to recreate something the <rect>
tag could do,
but these commands can be used to draw far more complex shapes than simple rectangles.
Commas are ignored in the
d
attribute — If they help you keep track of your coordinates (as they help me), then feel free to add them to your code.
Now that we know how to use the d
attribute with letter commands
to draw shapes, we can now take a look at getting curvy.
Drawing curves with the path tag
The <path>
tag has a few different ways of drawing curves, that fall under two
general categories: bezier curves and arcs.
Bezier Curves
If we want to build curvy lines, bezier curves are our first port of call. These curves are defined with control points, and as such they are relatively easy to visualise and define.
To draw a bezier curve in our <path>
, we can use some more letter commands, like we just learnt.
There are 2 types of bezier curves that can be drawn: cubic and quadratic.
Cubic bezier curves
To create a cubic bezier curve, we use the C
command.
C — Cubic curve (C dx1 dy1, dx2 dy2, dx dy
)
The syntax for defining a cubic curve takes 3 sets of coordinates: the first point’s control point (dx1 dy1
),
the second point’s control point (dx2 dy2
), and then then second point (dx dy
).
Use the interactive demo below to drag the control point handles to see how the control points affect the curve on the line:
If we are chaining cubic bezier curves, we can use a shorthand version for more succint markup:
S — Shorthand cubic curve (S dx2 dy2, dx dy
)
Using an S
command produces the same type of curve as using C
, but if it
follows another S command or a C command, the first control point is assumed to be a reflection of
the one used previously. Take a look at how that works:
Cubic bezier curves are quite simple to create, though not quite as simple as Quadratic bezier curves:
Quadratic bezier curves
The other type of Bezier curve, the quadratic curve requires just the single control point which determines the slope of the curve at both the start point and the end point.
Q — Quadratic curve (Q dx1 dy1, dx dy
)
This control points defines the curve, as seen here:
So quadratic curves are simpler to create than cubic curves, but don’t give us as much control over the curve itself.
T — Shortcut quadratic curve (T dx dy
)
As with the cubic curves, there is a shorthand way of writing quadratic curves, using the T
letter
command. This will assume a reflected control point, similarly to the shorthand cubic command. So in this
case, all we need to tell the curve is the next point of the line.
To recap what we have learned, these are the bezier curve commands we can use:
- C — Cubic curve (
C dx1 dy1, dx2 dy2, dx dy
) - S — Shorthand cubic curve (
S dx2 dy2, dx dy
) - Q — Quadratic curve (
Q dx1 dy1, dx dy
) - T — Shortcut quadratic curve (
T dx dy
)
Now to move on to the second category of curves we can create in an SVG — arcs.
Arc it up
Arcs are arguably the most difficult bit of learning SVG, but are the most powerful tool in it’s arsenal for drawing curves.
To start an arc, we use the A
letter command. Then we have to pass a whopping 7 numbers to the
definition:
A — Arc (A rx ry ellipses-rotation large-arc-flag sweep-flag x y
)
The arc command draws a curved line which is based on a segment of the edge of an oval/ellipses. Here is an example of an arc, and we can see how the arc is just a segment of the ellipses edge:
To break it down, here’s what each of those values is, specifically:
rx ry
: Radii of ellipse/s, respectivelyYes, radii is the plural form of radius, thank you very much. And okay, yes, I had to google it.
Anyhow, the rx ry
values lets us set the radius of the ellipses which will be used to form an arc.
ellipses-rotation
: Rotation of ellipse/s
The next value let’s us rotate those ellipses, in a rather straightforward sense:
large-arc-flag
: Flag to determine which ellipse line to draw to the end-point (1
for on, 0
for off)
The next value is a flag value, meaning it is either 0
for off, or 1
for on.
When a the ellipses cross over to form 2 arc, this flag determines whether to use the ‘long arc’ to create our arc (ie. the longer part of the ellipse).
sweep-flag
: Flag to determine which ellipse direction to draw to the end-point (1
for on, 0
for off)
The sweep_flag
specifies which side of the path the curve is drawn.
x y
: Co-ordinates of endpoint
Oh yeah, and finally, we will need to specify exactly where on the ellipses we want to segment our curve:
When you put all those pieces together, the arc command looks a litle something like this:
<path d="M0 0 A 100 200 30 0 0 200 200" />
The arc syntax is a little difficult to explain, but makes a lot more sense when visualised. Have a play around with the demo below to get an understanding of how each value does:
X Radius: 250
Y Radius: 250
Axis rotation: 0
The bezier and arc commands can seem intimidating when first encountered, but once we’ve got a handle on how their syntax works, they reveal themselves to be the secret sauce to creating complex and exciting graphics with SVG.
Choose your own path
That’s about all there is to know about defining a <path>
tag! Now we can start stringing those letter commands together and draw whatever the hell we damn well please.