Outils pour utilisateurs

Outils du site


issue138:inkscape

A quick summary: over the past few instalments, we’ve looked at a couple of animation techniques for SVG files. First was to use the animation capabilities of CSS, which has better support across browsers but is limited to animating those properties that can be exposed via CSS (i.e. the ones that will work in the “style” attribute). This covers a lot of possibilities, but does not include many of the core attributes that are found in SVG elements, such as their coordinates or path definitions. For some cases – such as transforms – enough of SVG’s capabilities have been added to CSS for such restrictions to be nothing more than an annoyance that can be worked around. For others, however, CSS simply isn’t up to the task. That’s where SMIL comes in. It’s an older specification for animation, created around the same time as the original SVG specs, and does provide the ability to animate arbitrary attributes in SVG. It can animate the “d” attribute that makes up the shape of a path, for example – a task that can only otherwise be accomplished in the browser via JavaScript. But although SMIL is more powerful than CSS in this regard, it has never been adopted in any Microsoft browser, leading to its inexorable decline and a likely deprecation in the browsers that do support it.

Résumé rapide : durant les quelques articles passés, nous avons regardé certaines techniques d'animation pour les fichiers SVG. La première consistait à utiliser les capacités d'animation du CSS, qui a un bon support des navigateurs, mais est limité à l'animation de celles des propriétés qui peuvent être affichées via CSS (c'est-à-dire, celles qui fonctionneront dans l'attribut « style »). Ceci recouvre un grand nombre de possibilités , mais ne comprend pas beaucoup des attributs centraux que l'on trouve dans les éléments SVG, tels que leurs coordonnées ou les définitions des chemins. Pour quelques cas, comme pour les transformations, suffisamment de possibilités ont été ajoutées au CSS afin que de telles restrictions ne soient rien d'autre qu'un désagrément qui peut être contourné. Toutefois, pour d'autres, CSS n'est pas à la hauteur de la tâche.

C'est là que SMIL entre en scène. C'est une spécification ancienne pour l'animation, créée à peu près au même moment que les spécifs du SVG d'origine, et il fournit la possibilité d'animer n'importe quel attribut dans SVG. Il peut animer l'attribut « d » qui suit la forme d'un chemin - une tâche qui ne peut être accomplie dans un navigateur autrement que via Javascript. Mais, bien que SMIL soit plus puissant que le CSS à cet égard, il n'a jamais été adopté dans un navigateur Microsoft, l'entraînant vers son déclin inexorable et une dépréciation probable dans les navigateurs qui le prennent effectivement en charge.

Given this situation, we won’t look any further at SMIL, but there are still a few tricks that can be performed with CSS that are worthy of further investigation. This time, we’re going to look at an increasingly popular animation technique which is really the result of taking a simple feature of SVG and pushing it in ways it wasn’t really intended for. It’s commonly referred to as “line animation”, although the line itself doesn’t change shape (remember, that can’t be done with CSS yet). It’s also sometimes referred to as a “self-drawing” image, which is a bit more descriptive: this technique results in a path that appears to be drawn on the screen in the same way as you would draw it with a pen. The first thing we’ll need is a path to animate. It should not have a fill, but will require a stroke. For this demonstration I’ve used Inkscape’s star tool to create an eight pointed star, then converted it to a path and roughly moved every second point inwards to give more of a cartoon gunshot appearance. I’ve given it a stroke-width of 2px and saved it using the “Optimised SVG” option in order to strip out most of the excess baggage from the file, just so that this tutorial isn’t filled with several pages of code.

Étant donné la situation, nous n'étudierons pas plus SMIL, mais il y a encore quelques astuces qui peuvent être réalisées avec CSS qui méritent une investigation plus poussée. Cette fois, nous regarderons une technique d'animation de plus en plus populaire qui est en fait le résultat du choix d'une simple fonctionnalité de SVG et de son utilisation dans des façons pour lesquelles elle n'était pas prévue. Il est classique d'y faire référence comme étant la « ligne animée », bien que la ligne elle-même ne change pas de forme (souvenez-vous que ça ne peut pas encore se faire avec le CSS). Cela est appelé aussi, parfois, une image « auto-dessinée », ce qui la décrit un peu mieux : cette technique crée un chemin qui semble être tracé sur l'écran de la même manière que si vous le traciez avec un stylo.

La première chose dont nous aurons besoin est un chemin à animer. Il ne devra pas avoir de remplissage, mais aura obligatoirement un contour. Pour cette démonstration, j'ai utilisé l'outil Étoile d'Inkscape pour créer une étoile à huit pointes, puis je l'ai convertie en chemin et j'ai rétracté grossièrement une pointe sur deux pour qu'elle ressemble plus à l'éclair d'un tir dans un dessin animé. Je lui ai donné une largeur de trait de 2 px et je l'ai sauvegardé avec l'option « SVG optimisé » de façon à supprimer la plupart de l'excédent de bagages du fichier, simplement afin que ce tutoriel ne soit pas rempli de plusieurs pages de code.

Opening the file in a text editor reveals a structure like that shown below. As you can see, it’s a pretty simple file. Even the <g> isn’t really needed, but it’s easier to leave it in place with its own transform, rather than try to manipulate the coordinates of the path to compensate for its removal. The secret to this animation technique is in the fact that SVG has a nice, simple, CSS-animatable way of drawing dashed and dotted strokes, rather than solid ones. The next step, therefore, is to introduce some dashes, defined in CSS. Note that you’ll probably have to also remove the corresponding properties from the path’s “style” attribute if you saved as a normal Inkscape file.

L'ouverture du fichier dans un éditeur de texte révèle une structure telle que celle montrée ci-dessous.

Comme vous pouvez le voir, c'est un fichier assez simple. Même le <g> n'est pas vraiment nécessaire, mais c'est plus facile de le laisser en place avec sa propre transformation, plutôt que d'essayer de manipuler les coordonnées du chemin pour compenser son retrait.

Le secret de cette technique d'animation réside dans le fait que SVG a une façon simple, animable avec CSS, de dessiner des contours tiretés et pointillés, plutôt que des traits continus. Par conséquent, l'étape suivante est d'introduire quelques tirets, définis dans le CSS. Notez que vous aurez aussi à enlever du chemin les propriétés correspondantes de l'attribut « style », si vous le sauvegardez dans un fichier Inkscape normal.

Save the file (top right) and load it directly into a web browser, and you should see something like this: The values we set in the stroke-dasharray property are used to determine the lengths of the drawn segments and gaps along the path. With our value of “10 2 3 5” the stroke will be drawn as a line segment of 10 units, followed by a gap of 2 units, then another line of 3 units and a gap of 5 units. The sequence then automatically repeats, so the next line segment is 10 units long and the next gap is 2. It runs around the path uninterrupted by corners, so a line segment (or gap) of 10 might appear as 3 units on one side of a corner and 7 on the other – look at the leftmost corner of the shape for a good example of this. If you follow the line round, taking that into account, you can see that the stroke dashes do follow the pattern we’ve set. This automatic repeating of values in the stroke-dasharray property produces a couple of neat features. The first is that any odd number of entries is effectively the same as writing a value that is twice as long, with the line and gap values swapped in the second half. So a value of “10 5 10” is the same as writing “10 5 10 10 5 10” – in other words a long line, short gap, long line then a long gap, short line, long gap. Notice that the length of the lines in the first half make up the length of the gaps in the second, and vice versa.

Sauvegardez le fichier (en haut à droite), chargez-le directement dans le navigateur Web et vous devriez voir quelque chose comme ceci :

Les valeurs que nous avons réglées dans la propriété stroke-dasharray (contour en pointillé) sont utilisées pour déterminer les longueurs des segments dessinés et des espaces le long du chemin. Avec notre valeur de « 10 2 3 5 », le trait sera dessiné comme un segment de ligne de 10 unités, suivi d'un espace de 2 unités, puis une autre ligne de 3 unités et un espace de 5 unités. La séquence est automatiquement répétée ensuite, de sorte que le segment suivant a 10 unités de long et l'espace suivant 2 unités. Elle se poursuit tout au long du chemin sans s'interrompre aux angles, de sorte qu'un segment de ligne (ou un espace) de 10 unités peut avoir 3 unités d'un côté de l'angle et 7 de l'autre - regardez la pointe la plus à gauche, qui en est un bon exemple. Si vous faites le tour en suivant la ligne, en prenant ceci en compte, vous pouvez voir que les morceaux du trait suivent le motif que nous avons paramétré.

Cette répétition automatique des valeurs de la propriété stroke-dasharray produit une paire de fonctionnalités bien sympas. La première est que tout nombre impair de valeurs saisies est en fait identique à la saisie d'une valeur deux fois plus grande, avec la permutation dans la deuxième partie des valeurs de lignes et d'espaces. Ainsi, une valeur de « 10 5 10 » revient au même que la saisie de « 10 5 10 10 5 10 » - en d'autres termes, une longue ligne, un espace court, une longue ligne puis un espace long, une ligne courte, un espace long. Notez que la longueur des lignes de la première moitié donne la longueur des espaces de la seconde, et vice-versa.

The other feature – and the one we’re interested in here – is that you can collapse the value down to a single number to get equal line and gap lengths. A lone value of “10” expands to “10 10”, giving you a repeating series of lines that are 10 units long, followed by gaps that are 10 units long. In my example file, that gives you something like this: Now consider what happens if we increase the value. As the number goes up, so the visible line segments get longer – but so do the gaps. Below is a sequence of screenshots of the same image with the stroke-dasharray value set to 10, 20, 50, 100 and 500. By the time we get to 500 our first visible line segment almost covers the entire path. If we were to continue increasing the value until it is the same as the path length, it would effectively render it the same as if we didn’t have the stroke-dasharray at all. And that’s exactly what we want to do!

L'autre fonctionnalité - et c'est celle qui nous intéresse ici - est que vous pouvez réduire la valeur à un seul nombre pour obtenir des longueurs de ligne et d'espace égales. Une valeur unique de « 10 » équivaut à « 10 10 », vous donnant une série répétée de lignes ayant une longueur de 10 unités, séparées par des espaces de 10 unités de long. Dans mon fichier exemple, cela vous donne quelque chose comme ceci :

Regardez maintenant ce qui se passe si vous augmentez la valeur. Plus le nombre croît, plus les segments de ligne grandissent, c'est pareil pour les espaces. Ci-dessous, une succession de copies d'écran de la même image où la valeur de stroke-dasharray est réglée à 10, 20, 50, 100 et 500, est présentée.

Quand nous arrivons à 500, notre premier segment de ligne visible couvre à peu près tout le chemin. Si vous continuez à augmenter la valeur jusqu'à ce qu'elle égale la longueur du chemin, le rendu sera identique à une absence de la propriété stroke-dasharray. Et c'est exactement ce que nous voulons faire !

You might be thinking it’s a little pointless to add a CSS property, then set it to a value that appears to have no effect, but remember that as well as the drawn line, there’s an equivalent length of gap that’s not visible because it extends beyond the end of the path. By adding another CSS property, however, we can adjust the start point of the drawn dashes, bringing our gap into play. The stroke-dashoffset property tells the browser to adjust its calculations to begin further into your stroke-dasharray sequence (note that the “px” here isn’t the same as screen pixels; rather it’s in the units of the SVG file, which are likely to be different to screen pixels due to scaling). If your dasharray is “10 5” and you set the offset to 3px then the first segment drawn will be only 7 units long, then a gap of 5, then a line of 10 and the rest continues as normal. In practice this means that setting a positive value here will “swallow” that much of the start of the stroke array, whereas a negative value will “push” the stroke array further along the path.

Vous pourriez penser que c'est sans intérêt d'ajouter une propriété au CSS pour la régler à une valeur qui la fait apparaître sans effet ; mais, souvenez-vous que de la même façon qu'il y a une ligne, un espace de même longueur existe qui n'est pas visible parce qu'il s'étend au-delà de la longueur du chemin. Cependant, en ajoutant une autre propriété du CSS, nous pouvons préciser le point de départ du dessin des tiretés, faisant entrer en jeu notre espace.

La propriété stroke-dashoffset (décalage du contour en pointillé) indique au navigateur qu'il doit ajuster ses calculs pour commencer plus avant dans la séquence de stroke-dasharray (notez que le « px » est ici différent des pixels de l'écran ; c'est plutôt l'expression des unités du fichier SVG, qui sont très probablement différentes des pixels de l'écran du fait de la mise à l'échelle). Si votre « dasharray » est de « 10 5 » et que vous réglez le décalage à 3 px, le premier segment dessiné n'aura plus que 7 unités de long, suivi d'un espace de 5 puis d'une ligne de 10 ; le reste se poursuit normalement.

En pratique, cela signifie qu'ici une valeur positive « avalera » d'autant le début de la séquence de traits, alors qu'une valeur négative « poussera » les traits successifs un peu plus loin le long du chemin.

By adjusting the value of stroke-dashoffset we can “slide” the drawn portion of the stroke along the path. Here’s what it looks like with values of 0px, 100px, 200px, 300px. Notice that progressively larger numbers swallow more of the path, showing more of the gap at the end. As you know, setting the dasharray to the same value as the length of the path will draw the entire path. But also setting the dashoffset to that value will then swallow the drawn segment, leaving only the gap (which is also the length of the path). In other words, our path will disappear completely. With the drawn segment completely swallowed, we’re at the starting point for our animation: our path is not visible on the screen. By decreasing the dashoffset value we can make the drawn segment creep onto the screen, following the shape of the path. All we need to do, therefore, is to animate the stroke-dashoffset value (see part 75 if you need a reminder of the animation syntax):

En ajustant la valeur de stroke-dashoffset, nous pouvons faire « glisser » la portion dessinée du trait le long du chemin. Voici à quoi il ressemble avec des valeurs de 0px, 100px, 200px, 300px. Notez que des nombres grandissants avalent peu à peu le trait, laissant apparaître plus d'espace à la fin.

Comme vous le savez, le réglage de dasharray à la même valeur que la longueur du chemin dessinera tout ce chemin. Mais si dashoffset est aussi réglé à la même valeur, le segment complet sera avalé, ne laissant apparaître que l'espace (qui a aussi la valeur de la longueur du chemin). En d'autres termes, notre chemin disparaîtra complètement.

Quand le segment dessiné est complètement avalé, nous sommes au début de notre animation : notre chemin n'est pas visible sur l'écran. En diminuant la valeur de dashoffset, nous pouvons faire ramper à l'écran le segment dessiné, qui suivra la forme du chemin. Par conséquent, tout ce dont nous avons besoin, c'est d'animer la valeur de stroke-dashoffset (voyez la partie 75 si vous avez besoin d'un rappel sur la syntaxe de l'animation).

Reload the file in your browser and you should see the effect we’re looking for – and because it’s all just CSS animation embedded directly in the SVG file, it will even work when the file is pulled into a web page via an <img> tag. Just a minute! Where did that value of 575 for the dasharray and dashoffset come from? As you’ve probably realised, that’s the total length of my path. You could theoretically get it from Inkscape via the Extensions > Visualise Path > Measure Path… extension, but that throws a Python error on my system. Alternatively you could just use trial and error: increasing the value of the dasharray until it just fills the path (which is quite easily done using the browser developer tools, if you’re familiar with them). The simplest option, though, is to ask the browser to do the hard work for you by invoking a little JavaScript. There is a method on the <path> object called getTotalLength() which will return the calculated length of the path. You can call it via the developer console in the browser, or modify your <svg> element to call the method when the file loads and display the value on screen. Here’s an example that will work for a file with a single path:

Rechargez votre fichier dans le navigateur et vous devriez voir l'effet que nous recherchons, et comme il s'agit simplement d'une animation du CSS directement intégrée dans le fichier SVG, il marchera même si le fichier est mis dans une page Web via une balise <img>.

Attendez une minute ! D'où vient la valeur de 575 mise dans dasharray et dashoffset ? Comme vous l'avez probablement réalisé, c'est la longueur totale du chemin. Vous pouvez théoriquement la trouver dans Inkscape via l'extension Extensions > Visualisation d'un chemin > Mesurer un chemin…, mais ceci déclenche une erreur de Python sur mon système. À la place, vous pouvez simplement le faire par tâtonnements : augmentez la valeur de dasharray jusqu'à ce que le chemin soit complètement rempli (ce qui se fait facilement en utilisant les outils pour développeur dans le navigateur, si vous êtes à l'aise avec eux).

Toutefois, l'option la plus simple consiste à demander au navigateur de faire le travail pour vous en invoquant un peu de Javascript. Voici une méthode de l'objet <path> appelée getTotalLength() qui retournera la longueur calculée du chemin. Vous pouvez l'appeler via la console de développeur du navigateur ou modifier votre élément <svg> pour appeler la méthode quand le fichier se charge et afficher la valeur à l'écran. Voici un exemple qui fonctionnera pour un fichier avec un seul chemin :

Remember that JavaScript won’t run when the document is loaded via the <img> tag, so to use the getTotalLength() method you will have to load the SVG file directly into the browser. You only need to do it once, then you can simply hard-code the value into the <style> block and remove the JavaScript code entirely. There is also an alternative to specifying the actual length of the path. You could add a “pathLength” attribute to the path, set it to a value of your choosing, then treat that value as the total length in the CSS. This basically tells the browser “I want to pretend this path is 100 units long, even though we both know it’s not, so can you just do the maths for me as needed”. A good compromise is to use JavaScript to find the actual length, then round it to the next whole number and set that value in the pathLength attribute and the CSS. That way any browser that understands pathLength will use it to give you a precise animation, and those that don’t are still using a value that’s close enough to work in most cases.

Souvenez-vous que Javascript ne se lance pas quand le document est chargé via la balise <img>. Aussi, pour utiliser la méthode getTotalLength(), vous devrez charger le fichier SVG directement dans le navigateur. Vous n'avez à le faire qu'une seule fois ; ensuite, vous pouvez simplement coder en dur la valeur dans le bloc <style> et retirer entièrement le code Javascript.

Il y a aussi une autre option pour spécifier la longueur réelle du chemin. Vous pouvez ajouter un attribut « pathLength » (longueur du chemin) au chemin, le régler à une valeur de votre choix, puis, dans le CSS, traiter cette valeur comme étant la longueur totale. Ceci dit en gros au navigateur « Je veux affirmer que ce chemin a 100 unités de long, même si nous savons tous les deux que ce n'est pas vrai ; aussi, pouvez-vous faire les calculs pour moi si nécessaire. » Un bon compromis consiste à utiliser Javascript pour trouver la longueur réelle, puis l'arrondir au nombre entier le plus proche et mettre cette valeur dans l'attribut pathLength et dans le CSS. De cette façon, tous les navigateurs qui comprennent pathLength l'utiliseront pour vous donner une animation précise et ceux qui ne le comprennent pas utilisent toujours une valeur qui est assez proche pour fonctionner dans la plupart des cas.

There’s one final thing to note with this approach. So far I’ve used the version of the technique you’ll most commonly find documented online, but, according to SVG expert Amelia Bellamy-Royds, the definition of stroke-dashoffset in the specification is vague enough that not all browsers behave identically. She suggests an alternative of forgetting dashoffset entirely and just animating stroke-dasharray instead. In this case, you need to include two numbers in the property as you need both the line and the gap to change together. My animation code then becomes that shown below. If you want to play around with this effect, but have the computer do a little more of the hard work for you, a discussion of this technique over on inkscapeforum.com led to one user creating an Inkscape extension that will add the CSS animation code for you. You can find the extension at https://gitlab.com/Moini/ink_line_animator/ and follow the original thread at http://www.inkscapeforum.com/viewtopic.php?f=5&t=33721

Une dernière chose est à noter dans cette approche. Jusqu'à maintenant, j'ai utilisé la version de la technique que vous trouverez généralement la plus documentée en ligne, mais, d'après l'expert en CSS Amelia Bellamy-Royds, la définition de stroke-dashoffset dans la spécification est suffisamment vague pour que tous les navigateurs ne se comportent pas de la même façon. À la place, elle suggère d'oublier totalement dashoffset et d'animer uniquement, stroke-dasharray. Dans ce cas, vous devez inclure deux nombres dans la propriété car vous avez besoin de changer en même temps la ligne et l'espace. Mon code d'animation devient celui présenté ci-dessous.

Si vous voulez tester cet effet, mais que vous voulez que l'ordinateur fasse pour vous un peu plus du travail difficile, un échange autour de cette technique sur le inkscapeforum.com a conduit un utilisateur à créer une extension d'Inkscape qui ajoutera pour vous le code d'animation dans CSS. Vous pouvez trouver cette extension à https://gitlab.com/Moini/ink_line_animator/ et suivre le fil initial à http://www.inkscapeforum.com/viewtopic.php?f=5&t=33721

Just animating a star being drawn is a little dull, but does show you the basic approach. Although the star contains no curves, this method works equally well with any shape of path. An easy step on from this, for example, would be to replace the star with a path for some handwritten text, to produce a “self-writing” effect. Be aware, however, that sharp transitions can cause rendering artefacts depending on the miter limit. In the case of my star, for example, the corner at the start/end of the line flashes on and off as the rest of the line is drawn. It’s often better to use rounded corners and end caps to avoid this, which also helps to reinforce the illusion of the line being drawn by a pen or pencil. If you’re prepared to spend more time hand-crafting your animations there’s no reason why you shouldn’t produce a self-drawing SVG image consisting of multiple paths, each animated separately using delays to ensure that they appear in the correct order. Once your outline is drawn, some more delayed animations could fade in the fill colours, erase some of the lines, or cross-fade to a raster image. With time and effort, this technique can produce some spectacular results, and all just by moving a dashed line around.

La simple animation du dessin d'une étoile est un peu terne, mais vous montre l'approche de base. Bien que l'étoile ne contienne aucune courbe, cette méthode fonctionne aussi avec n'importe quelle forme de chemin. Une étape suivante facile, par exemple, serait de remplacer l'étoile par un chemin de texte écrit à la main, pour produire un effet d'« écriture manuelle ». Cependant, sachez que les transitions brusques peuvent causer des erreurs au rendu en fonction de la limite de la pointe. Dans le cas de mon étoile, par exemple, le coin de début/fin de la ligne clignote pendant que le reste de la ligne est tracée. C'est souvent meilleur d'utiliser des arrondis aux coins et aux bouts pour l'éviter, ce qui aide aussi à renforcer l'illusion que le ligne est tracée avec un crayon ou un stylo.

Si vous êtes prêt à passer plus de temps à ajuster vos animations à la main, il n'y a aucune raison pour que vous n'arriviez pas à produire une image SVG de dessin automatique faite de chemins multiples, chacun animé séparément en utilisant des décalages de temps pour vous assurer qu'ils apparaissent dans le bon ordre. Une fois votre ligne générale tracée, certaines des animations retardées pourraient voir leur couleur de remplissage s'effacer, certaines lignes disparaître ou s'atténuer pour aller vers une image bitmap. Avec du temps et des efforts, cette technique peut produire des résultats spectaculaires, et tout cela juste en jouant avec une ligne en pointillé.

issue138/inkscape.txt · Dernière modification : 2018/11/11 16:08 de andre_domenech