Set to talk
Next to the <animate> element, <set> is impervious and imperative.
Specify the name of the attribute, a value, and the SVG element will assume the measure at once.
<circle r="5">
<set attributeName="fill" to="10" />
</circle> It is possible to delay the operation with the begin attribute, perhaps with a time offset, but the instruction is definite and clear. Without interpolation, the attribute is set in place.
Knowing this, it is possible to recreate a typewriter animation rather succinctly.
Letters
Instead of adding text directly in the <text> element.
<text>Hi there!</text> Break down the line into individual characters and with the appropriate <tspan> tags.
<text>
<tspan>H</tspan>
<tspan>i</tspan>
<!-- ... -->
</text> This is one place where JavaScript helps tremendously. And with Svelte, the authoring experience is simplified considerably with an each block.
<text>
{#each 'Hi there!'.split('') as letter}
<tspan>{letter}</tspan>
{/each}
</text> Whether you repeat the syntax yourself or rely on a utility, however, the result is the same. You have a series of neighboring <tspan> elements presenting the letters side by side.
Set
With multiple, sibling <tspan> the idea is rather simple:
hide the characters, for instance through the
opacityattribute<tspan> <set attributeName="opacity" to="0" /> {letter} </tspan>reset the value with a time delay
If you were to repeat the elements yourself you’d have to increase the offset for each additional
<tspan>, but with Svelte, theeachblock gifts an incrementing value as a second argument{#each 'Hi there'.split('') as letter, i} <!-- ... --> {/each}Inject the index with an arbitrary weight alongside the previous
<set>.<set attributeName="opacity" to="0" /> <set begin={i * 0.05} attributeName="opacity" to="1" />
With just two steps, the characters are shown in sequence. One by one.
But I might say, the characters should be shown in sequence. At least on Firefox and at the time of writing, the animation does not work. At fault, a puzzling and highly specific issue with the opacity attribute.
Set the value on any <tspan> element.
<text>Hi <tspan opacity="0">Firefox</tspan></text> And Firefox does not alter the opacity at all.
Ironic snippets aside, there is a way around the issue in the SVG spec.
Vector elements have a fill, and possibly a stroke. Conveniently, it is possible to alter the opacity of these portions with two distinct attributes: fill-opacity and stroke-opacity.
Update the code to use fill-opacity in place of the more general attribute.
-<tspan opacity="0">Firefox</tspan>
+<tspan fill-opacity="0">Firefox</tspan> And this time the instruction does work. Even in Firefox you find the short greeting.
And in the context of our typing animation, the characters are typed in, in their expected sequence.
There is a bug report detailing the problem, but until the issue is resolved, you find a quick alternative in more specific instructions.
To show you the animations at the press of a button I had to rely on JavaScript other than to save a few keystrokes. In this specific instance, I pause the <set> elements indefinitely.
<set begin="indefinite" attributeName="fill-opacity" to="1" /> And trigger the functionality through the node, on the basis of the current time.
const currentTime = svg.getCurrentTime();
set.setAttribute('begin', currentTime); For each additional element I increment the offset, always in the script, but you definitely do not need such a roundabout setup to play the animation as you code along. There is plenty you achieve with SVG syntax, SMIL and without a script.
With SVG syntax you can draw crisp visuals to honor a beloved title from long ago.
With SMIL you can take the <set> element and experiment a bit more with the animation. After all, there is no particular reason that pixelated phone is sitting in an empty room, is there?