Drawing with Dashes
One of the most popular SVG animations uses stroke dashing to imitate the effect of a path being drawn from one end to the other.
The concept: start with a dash pattern where the entire shape is covered by a gap, and then adjust it until the entire shape is outlined by a single dash.
As you can imagine, the getTotalLength()
method introduced in the book is essential for determining how long your dash and gap need to be to cover the entire stroke. To recap:
-
path.getTotalLength()
returns a positive number that is the length of the path outline, measured in the user units (px units) of the local coordinate system. -
The length includes all sub-paths, but doesn’t include any jumps from move-to commands in the middle of the path.
-
You can use the method in JavaScript that will run on your website, or you can use your browser Dev Tools as a calculator, selecting the shape and calculating a length value, which you then use in your SVG or CSS code.
Because browser length calculations vary, if you’re hard-coding the numbers in advance you’ll want to slightly overestimate the length required, so that the entire path will start empty and finish stroked, in any browser.
However, if you’re animating with JavaScript anyway, it is better to can calculate the path length dynamically in the current browser, so it is always exact. You can also use JavaScript to calculate a value that you set in an inline style, which is particularly useful in combination with CSS variables.
But beware: most browsers still only support getTotalLength()
on <path>
elements. In SVG 2 and in new versions of Chrome, it is supported on all SVG shape elements.
There are two variations of the drawing animation method:
-
Use a fixed dash pattern consisting of a dash that is the full length of the path followed by a gap the full length as well. You can create this pattern with a single value (equal to the path length) in the
stroke-dasharray
property, since a single value will automatically be duplicated to create identical dash and gap values.Then, animate the
stroke-dashoffset
from the full length down to 0 to move the single dash into place. -
Animate
stroke-dasharray
directly, from a zero-length dash and full-length gap, to a full-length dash and zero-length gap.The
stroke-dashoffset
can be whatever you want, to control the point on the path where the drawing effect starts from.
Warning
Certain SVG implementations, including older Firefox versions on Linux systems, implemented stroke-dashoffset
in such a way that negative and positive offsets had the reverse effect. This causes the stroke-dashoffset
drawing animation to run backwards. For consistent results, animate stroke-dasharray
, not the dash offset.
Example 13-X1 uses a CSS animation sequence of stroke-dasharray
to complete the outlines of the heart and spade icons. It then fades in a fill color inside the outlined shapes. Figure 13-X1 compares different stages of the animation.
Example 13-X1. “Drawing” a shape by animating a dash pattern
<svg
xmlns=
"http://www.w3.org/2000/svg"
xml:lang=
"en"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"410px"
height=
"205px"
viewBox=
"-1 -1 44 22"
>
<title
>
Drawing SVG Shapes
</title>
<style
type=
"text/css"
>
path
{
stroke-dashoffset
:
-1
;
stroke-linejoin
:
round
;
stroke-linecap
:
round
;
animation
:
draw
5s
ease
-
in
;
}
@keyframes
draw
{
0%
{
stroke-dasharray
:
0
83
;
fill-opacity
:
0
;
}
90%
{
stroke-dasharray
:
83
0
;
fill-opacity
:
0
;
}
100%
{
stroke-dasharray
:
83
0
;
fill-opacity
:
1
;
}
}
</style>
<path
id=
"heart"
stroke=
"darkRed"
fill=
"crimson"
d=
"M10,6 Q10,0 15,0T20,6Q20,10 15,14 T10,20Q10,18 5,14T0,6Q0,0 5,0T10,6Z"
/>
<path
id=
"spade"
stroke=
"#222"
fill=
"gray"
transform=
"translate(22,0)"
d=
"M9,15C9,20 0,21 0,16S6,9 10,0C14,9 20,11 20,16 S11,20 11,15Q11,20 13,20H7Q9,20 9,15Z"
/>
</svg>
To avoid having a dash end exactly at a corner—ruining a line join—the dash pattern is offset by 1 unit. With the
round
line joins and caps used here, the difference will not be noticeable, but with other styles it would be.The animation property applies the
draw
keyframes, timed to last 5s, with no repeats, and uses anease-in
mode to slowly ramp up the rate of change to full speed.The initial value of the animation is set using the
0%
keyframe selector. It setsfill-opacity
to 0 (completely transparent) andstroke-dasharray
to a zero-length dash followed by an 83-unit gap. The length of 83 was chosen because it is slightly larger than the longest path length calculated for the spade in any browsers tested. The heart—which has a shorter path length—will be fully stroked before the animation is completed.After 90% of the animation time has passed, the
stroke-dasharray
has transitioned to an 83-unit dash and zero-length gap. Thefill-opacity
, however, is still 0.The transition to the final keyframe keeps
stroke-dasharray
the same, but shiftsfill-opacity
to completely opaque.
Because the stroke-dasharray
and fill-opacity
properties are only set within the animation keyframes, browsers that do not support animation will simply present the shapes fully stroked and filled. As we will discuss in Chapter 19, it’s a good idea to always consider the fallback static version of your animated SVG. For “enter” animations like this, you usually want that static graphic to be the final appearance.