Outils pour utilisateurs

Outils du site


issue137:inkscape

Ceci est une ancienne révision du document !


Last time, we looked at how to animate an SVG element using SMIL rather than CSS animations. We’ll continue with this topic for one more article, but my warnings from last time need to be repeated: although SMIL is (currently) more capable and flexible than the CSS option, Microsoft have chosen not to implement it in any of their browsers, leading to a slow but inexorable demise in support across all the browser vendors. For the time being, it still works in most browsers but, unfortunately, this is not a technology to bet on in the long term.

I much prefer SMIL to CSS animations. I find the code easier to understand, and the fact that the animation data tend to live inside the elements they’re animating avoids any confusion as to which rules apply to which objects as your document becomes more complex.

With a complex document it becomes ever more likely that your animations won’t all have to run at the same time, but instead might run sequentially – or a mixture of both. Consider trying to animate something as sophisticated as a cartoon: being able to finely adjust the timing of each character’s movements is essential. CSS animations offer little to help you in this case, other than the brute-force option of adding a delay to your animations with this the sort of approach (shown right).

Here we’re changing the fill color of a pair of rectangles (with IDs of “rect1” and “rect2”). The first changes from red to blue over 3 seconds. After a 3 second delay, the second rectangle changes from red to white over a 5 second period. Due to that 3 second delay, the animations occur sequentially.

Now what happens if you want to change the length of the first animation? You must also keep the delay for the second animation synchronised to the same value, otherwise it will either overlap the first, or occur some time after the first has finished. CSS does now support variables, so you can set the animation length once and reuse it as necessary, but the syntax is ugly and unwieldy (previous page, bottom right).

Now imagine what your CSS would look like when you want to chain five animations, or ten – or a hundred! How much better it would be if you could just tell the second animation that it should start when the first one finishes. With SMIL, that’s exactly what you can do. The SMIL animation elements have an optional “begin” attribute which allows various ways of defining when the animation should start. At its simplest, you can just enter a delay, giving the same effect as the CSS animation above (shown top right).

But you can also define the beginning of an animation to be triggered by the end of another by using the ID of the other animation, followed by “.end” (bottom right).

What happens if we want to change the length of the first animation now? No problem! Just modify the “dur” attribute and the second animation will still dutifully follow after the end of the first one. As well as the “.end” syntax you can also use “.begin” to link animations together so that they always start at the same time. You can optionally add an offset, such as “anim1.begin+2s” to make the animation begin 2 seconds after “anim1” starts, or even “anim1.end-0.5s” if you want your animation to begin half a second before the end of “anim1”.

SMIL allows animations to be repeated by adding a “repeatCount” or “repeatDur” attribute. For example, repeatCount=“5” would cause the animation to repeat five times, whilst repeatDur=“01:00” would cause it to repeat for one minute. When a repeating animation is used as the trigger for a second animation, this also allows an additional syntactic form to be used: begin=“anim1.repeat(2)” would cause the second animation to begin immediately after the second repeat of anim1 completes. Again, changes to the duration or start time of anim1 are automatically handled for you.

In theory, these values can also be used for the “end” attribute, rather than for “begin”. That should allow you to specify that a second animation should finish three seconds after the end of the first animation, with the browser calculating when the animation should start in order to produce that result. Similarly, you should be able to specify values for “begin” and “end” with no duration set. In practice browsers fail to honor anything but a simple time-based “end” value.

Speaking of features that don’t work in the browsers, the “begin” (and “end”) attributes can, theoretically, take several other forms. You should be able to use an ISO8601 format time or datetime value to trigger your animation at a particular absolute time, but I was unable to get that to work in a browser. Another option is an “accessKey” - i.e. a single key on the keyboard that, when pressed, would trigger the start of the animation. The presence of a demo for this on the Mozilla developer site suggests it used to work, but neither Firefox nor Chrome behaved as expected in my own tests.

There’s one final option that does sort-of work, however: events. The following syntax, for example, will (in principle) trigger an animation when the rectangle is clicked on:

<rect id=“rect1” fill=“#f00” …>

<animate id="anim1"
  attributeName="fill" 
  from="#f00" to="#00f" 
  dur="3s" fill="freeze"
  begin="rect1.click" />

</rect>

There are various events available, covering not only clicks but also mouse movements, scrolling and even changes to the structure of the document. Although the example above uses the parent element to trigger the animation, in practice you could use the ID of another element in the image – allowing a click on one element (styled as a Start button, perhaps) to trigger an animation on another.

In practice this option does work, but only in situations when JavaScript would also be executed: when the SVG image is loaded directly, via an <object> tag, or is included inline with the HTML. It doesn’t work when SVG is loaded via an <img> element, which is a real shame as it could theoretically offer a safe way to produce interactive animations without the security risk of allowing JavaScript code to run.

And that pretty much sums up the failed promise of SMIL. If fully implemented it would have allowed the creation of complex animations triggered by mouse events or keypresses, with each component synchronised to other parts, all with a fairly simple declarative syntax that makes it safe to use via an <img> tag. Imagine a complex interactive animation, of the sort that you might see in a museum, but with the ability to be shared on forums or social media as easily as any other image.

Before bidding farewell to SMIL entirely, I’m going to briefly discuss the last of the animation elements that are supported by SVG: <animateMotion>. This allows you to animate the position of an element along a path, either defined within the element itself or by reference to another path in the file. Consider this delightful evening scene (below).

Note the orange path across the night sky, which I’ve given an ID of “animPath”. The yellow shooting star is made up of a group of objects, drawn so that the center of the star is at the top left of the document area (0,0 in SVG coordinates) – though I’ve moved it into the middle of the scene for this screenshot so that you can see it. By adding an <animateMotion> section inside the group, the shooting star will follow the orange path across the night sky (top right).

The <animateMotion> element gets the usual animation attributes of “dur” and “fill” (and could have had “begin” and “end” if required), but has two attributes that are specific to this type of animation. The first is a “d” attribute which can contain path data of the same form that you would find in a <path> element. If present, this is used as the path along which the parent element will be animated.

An alternative to directly including the path data in the <animateMotion> is to reference a separate path that is present elsewhere in the document. This is the approach I’ve taken here, by including an <mpath> (“motion path”) child element that refers to the ID of our animation path via the “href” attribute. Although modern browsers understand “href” as a native attribute in SVG, using the “xlink” namespace provides better compatibility with older software, so that’s what I’ve done here. The big advantage of using a linked path like this is that the path is an element that can be modified in Inkscape, whereas an embedded “d” attribute isn’t.

The second attribute that is specific to <animateMotion> is “rotate”, which is an SVG addition which is not present in the base SMIL specification. This can take a number, in which case the object is rotated by that number of degrees, although a fixed rotation is probably better achieved using a “transform” attribute. More usefully, this attribute can take a value of “auto”, in which case the rotation of the element follows the shape of the path (there’s also an “auto-reverse” option which does the same, but rotates the animated element through 180° first). Here’s the effect of each option as the star descends on its path; notice particularly how rotate=“auto” has turned it to suit the descending curve of the line.

You may be wondering about that orange path. The final step in designing an animation like this is typically to hide the animation path somehow. I usually move the path down in the z-stack behind everything else, or change its stroke color or opacity to make it transparent. Even when it’s transparent you can still get to it using Inkscape’s View ‣ Display Mode ‣ Outline option, if you do need to make some later changes. Although this simple example uses just a single curved path segment, the animation path can be as complex as you like with loops, twists, curves and sharp corners, so being able to tweak it graphically in Inkscape can be invaluable.

One final thing to note is that although my test animation ran smoothly in both Chrome and Firefox when the SVG file was loaded directly, referencing it via an <img> tag in a web page resulted in a choppy animation in Firefox.

I’ll leave you with a little SMIL anecdote: back in 2011 I made use of SMIL for an Easter egg in one of my webcomics, to animate a UFO flying over the scene. The animation path itself is seemingly jerky and erratic, but digging into the file in Inkscape reveals that the path actually encodes a URL. Visiting that address shows a small demo of what SMIL can do: by using some JavaScript to dynamically add and modify SVG and SMIL elements, I wrote a simple Space Invaders style game that runs in the browser. JavaScript handles the game logic, with SMIL responsible for ensuring that the flying saucers move smoothly around the sky. For the time being, at least, it runs in all the major browsers, except Microsoft’s…

These couple of articles have just provided a brief introduction to SMIL. With browser support waning, it’s unlikely to ever fulfill its early promise of allowing interactive animations in a way that can be safely used online anywhere a simple image is allowed. As is too often the case, it appears that corporate politics has killed a promising technology.

issue137/inkscape.1538411195.txt.gz · Dernière modification : 2018/10/01 18:26 de auntiee