Accueil > Développement Web > Animation avec SVG

Animation avec SVG

Par Antoine Quint

Traduit par Olivier, le 21/01/2003

Pour pouvoir afficher les exemples SVG, vous aurez besoin d’avoir installé le module d’affichage SVG d’Adobe.

Introduction

Internet n’a pas cessé d’évoluer depuis qu’il est apparu il y a une dizaine d’années. Les jours des sites affichant des pages de textes simples sont révolus et les graphiques vectorisés, entre autres, sont devenus aujourd’hui choses communes. SWF, le format utilisé par Flash de Macromedia, est devenu le média de choix pour les présentations animées et hautes en couleurs. Cependant, SWF a des limites, l’édition dynamique en étant une importante. Si vous lisez cet article, c’est que vous avez probablement entendu un peu parler d’un format de dessin vectoriel émergeant, basé sur XML, appelé SVG. Aujourd’hui nous allons commencer notre incursion dans le fabuleux monde de l’animation SVG.

L’animation est une caractéristique majeure de SVG. C’est une part importante des spécifications de SVG, basées sur l’animation SMIL.
En fait, si vous connaissez déjà l’animation SMIL alors cet article vous paraîtra comme une petite remise en jambes.
Avant de commencer, il pourrait être intéressant de récupérer le chapitre des spécifications de SVG.
Ma mission à travers cet article est de vous montrer comment recréer une de ces superbes animations utilisant les lois de la gravité qui enchantent les gens pendant des heures.
SVG n’en fera pas une animation plus utile que si elle avait été implémentée en Flash, mais cela sera certainement très instructif.
Pour avoir un avant goût de ce que nous allons créer, jetez un coup d’oeil à l’animation SWF de Niklas Gustavsson, même si nous allons y ajouter quelques améliorations.
Lancer votre éditeur de texte favori et nous pourrons commencer !

Créer les Graphiques

Niklas a eu la bonté de bien vouloir fournir le code source de son animation sur son site, ce qui va nous aider à créer une animation similaire en SVG.
J’ai téléchargé le code source, ouvert dans Macromedia Flash 5, sélectionné un des petits cubes, que j’ai copié dans le presse-papier.
Puis j’ai pris un de mes outils SVG préféré, Illustrator 10 d’Adobe, créé un nouveau document et collé le cube à l’intérieur.
A partir de là, il est possible de travailler avec SVG, donc je sauvegarde le document au format SVG.
Voici ce sur quoi nous allons travailler :


<?xml version="1.0" encoding="iso-8859-1"?>

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">

<svg width="665px" height="250px" viewBox="0 0 665 250"
     xml:space="preserve">

  <g id="cube" style="stroke: #000000; stroke-width: 0.5;
                      stroke-linejoin: bevel">
    <path style="fill: #333333;" d="M0.112,26.271l25.032,
                      12.485V25.164L0.112,12.68V26.271z"/>
    <path style="fill: #666666" d="M25.144,38.756l25.033-
                      12.485H50.12V12.708L25.144,25.164V38.756z"/>
    <path style="fill: #cccccc" d="M50.12,12.708l0.057-
                      0.028L25.144,0.224L0.112,12.68l25.032,
                      12.484L50.12,12.708z"/>
  </g>

</svg>

[Voir le code en SVG]

Maintenant ce que nous allons faire c’est prendre ce groupe de petits cubes (compris entre les balises de l’élément <g>) et le transformer en un symbole SVG que nous pourrons réutiliser comme bon nous plaira. C’est assez simple en fait, remplacez simplement le groupe en un symbole et ajouter le en tant que définition. On place ensuite le cube au centre de la composition et on ajoute le rectangle gris au fond de façon à nous rapprocher du style de Niklas. Nous donnerons également à cette composition un titre. Maintenant notre code ressemble à ce qui suit. A partir de maintenant, nous considérerons ceci comme acquis et nous n’afficherons plus le doctype et les définitions :


<svg width="665px" height="250px" viewBox="0 0 665 250"
     xml:space="preserve">

  <title>SVG Animation - Cube Demonstration</title>

  <defs>
    <symbol id="cube" style="stroke: #000000; stroke-width: 0.5;
                             stroke-linejoin: bevel">
      <path style="fill: #333333;" d="M0.112,26.271l25.032,
                        12.485V25.164L0.112,12.68V26.271z"/>
      <path style="fill: #666666" d="M25.144,38.756l25.033-
                        12.485H50.12V12.708L25.144,25.164V38.756z"/>
      <path style="fill: #cccccc" d="M50.12,12.708l0.057-
                        0.028L25.144,0.224L0.112,12.68l25.032,
                        12.484L50.12,12.708z"/>
    </symbol>
  </defs>

  <rect width="100%" height="100%"
        style="fill: #999999; stroke: none;" />

  <use xlink:href="#cube" transform="translate(307.5, 105.75)" />

</svg>

[Voir le code en SVG]

Commençons Doucement (et de Façon Linéaire)

Maintenant que le graphique est prêt, nous devons commencer avec un peu d’animation. Je dois cependant vous avertir : si vous pensiez que cela serait difficile, cela sera en fait facile ! La première chose que je veux vous montrer est comment effectuer une animation linéaire du cube qui se déplacera vers le haut puis vers la bas, vers le haut puis vers le bas (et ainsi de suite). Nous avons placé notre symbole dans le graphique en utilisant l’attribut “transform”, qui, bien qu’ayant déplacé le symbole dans l’image, a laissé l’attribut de coordonnée “y” du symbole à sa valeur par défaut de “0″. Donc si nous voulons que l’animation de notre objet soit un déplacement vertical, nous changeons simplement l’attribut “y” de la valeur de déplacement et nous laissons le “transform” pour le positionnement de départ.


<use xlink:href="#cube" transform="translate(307.5, 105.75)">
  <animate attributeName="y" dur="2s"
           values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0" />
</use>

[Voir le code en SVG]

C’est un début. Ce que nous avons fait ici c’est d’ajouter un élément “animation”, fils de notre élément “use” et initialiser quelques uns de ces attributs pour lui conférer son comportement. L’attribut “attributeName” nous permet de spécifier l’attribut de notre élément “use” qui sera animé. Ceci met en évidence une des caractéristiques principales de l’animation SVG : elle est orientée propriété. Cela signifie que chacune des propriétés d’un élément SVG (que ce soit des attributs XML ou CSS) possède son propre environnement d’animation par défaut qui est unique et indépendant. Ce qui permet de réaliser des choses intéressantes, la principale étant qu’un élément peut avoir des propriétés animées ayant différentes durées de boucle, compteurs de boucle ou autres. Ceci est d’une aide précieuse lorsque l’on essaie de créer des animations aléatoires. Si vous êtes familier avec l’outil Flash, vous savez que vous avez besoin de clips vidéo pour obtenir ce comportement, ce qui est déjà d’un niveau avancé. L’animation SVG rend les choses simples. De plus, l’animation SVG nous permet de créer des relations en vue de synchroniser différentes animations afin que l’indépendance temporelle ne soit pas exclusive (plus sur ce sujet plus loin).

A propos de l’animation que nous venons juste d’écrire, vous remarquerez que nous avons également spécifié la durée de l’animation. L’attribut “dur” détermine la durée, et ici nous avons spécifié que notre animation durera “2s”, deux secondes. Ceci est un autre point intéressant de l’animation SVG : elle est basée sur le temps. Encore une fois, si vous avez de l’expérience avec Flash, vous remarquerez que c’est un outil basé sur les images, l’axe du temps étant gradué en unités d’images. Cela signifie qu’il est nécessaire de spécifier une fréquence d’images lors de l’édition de l’animation SWF.

LiveMotion d’Adobe (un autre outil SWF) propose un axe du temps basé sur le temps, mais doit quand même générer une animation basée sur les images lors de l’exportation au format SWF. Je pense que le fait d’être basé sur le temps est un avantage pour SVG, car il nous permet de définir des animations qui évoluent dans un système unitaire réaliste (le temps) et délègue la conversion en fréquence d’images au module d’animation SVG, qui essaiera sans doute d’utiliser au mieux votre processeur pour présenter de belles animations bien fluides. Au fur et à mesure de la construction de notre exemple, vous réaliserez peut-être que le modèle de représentation d’animation de SVG est assez différent de celui de SWF. Un outil d’édition SWF calculera toutes les images lors de l’export alors que l’animation SVG laisse le travail de calcul au module d’animation SVG. Ceci permet souvent d’obtenir des tailles de fichiers plus petites mais demande un capacité de calcul plus importante au niveau du périphérique. Or le calcul des images de l’animation n’est pas la phase la plus exigeante de l’animation, alors que l’affichage est certainement le plus exigeant.

Mais je m’éloigne du sujet. Nous avons presque oublié de parler de cette mystérieuse liste de valeurs séparées par des points-virgules dans l’attribut “values”. En fait, il s’agit simplement de la liste des valeurs qui seront assignées à notre “attributeName”, un peu comme les “keyframes” dans Flash. Par défaut, un module d’animation SVG calculera une interpolation linéaire entre chaque valeur, créant ainsi l’animation. De plus, il effectuera ces changements de valeurs l’un après l’autre à intervalles réguliers, dont le nombre est équivalent à la durée de l’animation divisée par le nombre de valeurs dans la liste, moins une.

Prise en Compte de la Souris

Jusqu’à présent le travail que nous avons fait, bien qu’utile, est un peu limité. Niklas avait fait en sorte que ses cubes réagissent aux événements générés par la souris lorsque l’utilisateur la déplace dessus. Faisons en sorte de faire de même. L’animation SVG propose un mécanisme pour réagir aux événements souris. Vous avez peut-être remarqué que dans notre animation précédente, nous ne spécifions pas quand l’animation doit être déclenchée. Il existe un attribut “begin” qui est approprié pour cela, mais sa valeur par défaut est de “0s”, c’est à dire que l’animation ne démarre que lorsque le document est chargé. Maintenant, nous voulons que l’animation démarre quand la souris passe au-dessus du cube. Essayons d’introduire l’attribut “begin” dans notre animation, initialisons le à “mouseover”, et voyons ce qui se passe :


<use xlink:href="#cube" transform="translate(307.5, 105.75)">
  <animate attributeName="y" begin="mouseover" dur="2s"
           values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0" />
</use>

[Voir le code en SVG]

Si vous déplacez la souris au-dessus du cube, vous remarquerez que cela déclenche l’animation. Vous remarquerez également que le comportement est un peu étrange. Si vous ne déplacez pas le pointeur hors de la zone où vous êtes passé au-dessus du cube, déclenchant ainsi l’animation, alors l’animation recommence depuis le début. Ce n’est pas ce que nous recherchons ; nous ne voulons pas que le cube gère les événements souris tant que l’animation n’est pas terminée. Une fois encore, l’animation SVG nous offre le mécanisme exacte que nous recherchons : l’attribut “restart”. Par défaut, sa valeur est initialisée à “always”, ce qui signifie que l’animation est redémarrée chaque fois que la situation spécifiée par l’attribut d’animation “begin” est vérifiée. Une autre valeur possible est “whenNotActive”, qui selon les spécifications signifie que “l’animation ne peut-être rédémarrée que si elle n’est pas active [et que toutes les] tentatives pour redémarrer l’animation durant son déroulement seront ignorées”. Cela ressemble à ce que nous recherchions, voyons son implémentation :


<use xlink:href="#cube" transform="translate(307.5, 105.75)">
  <animate attributeName="y" begin="mouseover" restart="whenNotActive"
           dur="2s"
           values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0" />
</use>

[Voir le code en SVG]

C’est exactement le comportement que nous souhaitions. Très bien. Cependant il nous reste pas mal de choses à faire pour obtenir une animation aussi bien finie que l’originale. Continuons donc.

Le Rythme s’accélère

L’ingrédient essentiel pour rendre notre animation aussi éclatante que celle de Niklas est l’accélération/décélération dûes à la force de gravité. Quand j’ai ouvert le code source dans Flash, j’ai remarqué que Niklas avait fait deux choses. La première étant d’ajuster la fréquence d’images pour faire en sorte que l’animation ait différents intervalles entre deux ensembles de valeurs. La deuxième étant d’avoir utilisé une sorte de fondu enchaîné entre certains intervalles de l’animation. Voyons comment nous pouvons implémenter cela en SVG : gardez vos yeux ouverts parce que ceci est ce que l’animation SVG a de plus intéressant à proposer.

Notre première tâche est de déterminer les valeurs à prendre en compte à différent intervalles de temps. Nous allons introduire un nouveau membre de notre groupe croissant d’amis : l’attribut “keyTimes”. Cet attribut va nous permettre de recréer le rythme que l’on peut observer dans l’animation SWF d’origine ; il va nous permettre de créer un lien entre les attributs “values” et le moment auquel chaque valeur sera atteinte lors de l’animation. La spécification SVG nous dit que “chaque valeur dans la liste keyTimes doit être un nombre décimal compris entre 0 et 1 (inclus), représentant un déplacement proportionnel à la durée de l’élément d’animation”. Bien que cela soit dit en termes très formels, c’est ce que nous recherchons. Essayons :


<use xlink:href="#cube" transform="translate(307.5, 105.75)">
    <animate attributeName="y" begin="mouseover"
             restart="whenNotActive" dur="2s"
             values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0"
             keyTimes="0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
                       0.7949; 0.8462; 0.8974; 0.9231; 0.9487;
                       0.9744; 1" />
  </use>

[Voir le code en SVG]

Ne faites pas attention aux valeurs bizarres que nous avons mis dans l’attribut “keyTimes”. Elles ont été calculées à la main d’après l’animation Flash d’origine. Ces valeurs semblent étranges parce que les “keyframes” de Niklas étaient placées à des instants étranges. Ce travail se fait normalement au niveau de l’éditeur SVG, mais comme nous essayons de comprendre comment l’animation SVG fonctionne cela vaut la peine de le faire à la main. Il en résulte une animation un peu plus rythmée. Elle n’est toujours pas exactement comme celle de Niklas, mais la fin ressemble à ce qu’elle devrait. Concernant le début de l’animation, c’est là que Niklas utilise un fondu enchaîné. Faites bien attention parce que cela va se fluidifier.

Dans Macromedia Flash 5, il est possible de spécifier un fondu enchaîné entre deux keyframes avec un pourcentage allant de “-100%” à “100%”. Bien que ce soit un contrôle pratique de l’accélération, SVG propose un mécanisme encore plus pratique. Au lieu d’avoir un simple pourcentage, SVG nous permet de spécifier le comportement de la vitesse de l’animation entre deux intervalles à l’aide d’une courbe de Bézier à deux points (vous avez probablement beaucoup entendu parler de ces dernières si vous avez un peu d’expérience avec SVG). Qu’est-ce-que cela veut dire ?

Dessinez une courbe de Bézier qui tient dans un carré, débutant dans le coin inférieur gauche et se terminant dans le coin supérieur droit. La règle pour dessiner ce type de courbe est qu’elle doit être bijective (une correspondance unique entre x et y). Vous pouvez trouver un certain nombre de ce genre de courbes juste au dessus de la section 19.2.8 de la spécification, qui sont très pratiques pour voir comment fonctionnent les keySplines. L’axe des x représente le temps et l’axe des y représente le pourcentage de variation entre les deux valeurs. Cela nous permet d’avoir un contrôle très fin de la vitesse d’animation. Alors que Flash ne nous permet que de spécifier une vitesse de variation constante, SVG nous offre plusieurs vitesses de variations dans un intervalle donné. Maintenant que nous avons une meilleure idée de la manière dont les keySplines fonctionnent, employons cette nouvelle connaissance à notre projet :


<use xlink:href="#cube" transform="translate(307.5, 105.75)">
    <animate attributeName="y" begin="mouseover"
             restart="whenNotActive" dur="2s" calcMode="spline"
             keySplines="0 .75 .5 1; .5 0 1 .25; 0 .25 .25 1;
                         .5 0 1 .5; 0 0 1 1; 0 0 1 1; 0 0 1 1;
                         0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1"
             values="0; -45; 0; 16; 0; -7; 0; 3; 0; -2; 0; 1; 0"
             keyTimes="0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
                       0.7949; 0.8462; 0.8974; 0.9231; 0.9487;
                       0.9744; 1" />
  </use>

[Voir le code en SVG]

Maintenant l’animation est belle, très proche de l’originale, et en fait bien plus fluide puisque nous n’avons pas à nous soucier de la fréquence d’images, peu parlante. En plus de l’attribut “keySplines” que nous venons juste d’introduire, vous aurez remarqué un nouvel ami : “calcMode“. Cet attribut permet des ajustements sur l’interpolation entre deux valeurs d’animations. Jusqu’à présent, nous avons utilisé sa valeur par défaut (”linear”) et maintenant nous avons besoin de l’initialiser à “spline” pour que notre attribut “keySplines” soit pris en compte.

Allez et Multipliez-Vous !

Une des dernières choses à faire est de créer seize instances de notre cube. Comme nous avons défini notre cube en tant que “symbol” SVG, il nous suffit de placer seize éléments “use”, un peu comme nous avons fait jusqu’à présent avec notre cube simple. Je ne vais pas vous apprendre comment aligner les cubes, car j’ai en fait utilisé Illustrator pour obtenir la boîte des cubes et je les ai vaguement arrangés à la main (vous pouvez voir en zoomant que l’alignement n’est pas parfait).

De même que nous avons créé un symbole pour le graphique pour qu’il puisse être réutilisé, nous pourrions créer une référence pour notre animation puisque tous les cubes sont animés de manière identique. Nous aurions pu avoir notre élément “animation” défini dans le symbole, mais les spécifications SVG 1.0 précisent que dans ce cas, toutes les instances du symbole seraient animées en même temps. Cependant, la référence à une animation est un problème qui est en train d’être étudié par le Groupe de Travail SVG du W3C pour des améliorations futures, et SVG 1.1 (pour l’instant à l’état d’avant-projet) introduit un mécanisme permettant l’animation d’instances de symboles uniquement. Il existe quand même une manière de recréer ce comportement en utilisant des entités. L’idée est de centraliser toutes les valeurs sensibles de notre animation, celles qui auront tendance à être modifiées, afin qu’une modification s’applique à toutes les animations. Comme ceci :


<?xml version="1.0" encoding="iso-8859-1"?>

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [
  <!ENTITY dur "2s">
  <!ENTITY values     "0;    -45;      0;     16;      0;     -7;
                       0;      3;      0;     -2;      0;      1; 0">
  <!ENTITY keyTimes   "0; 0.2564; 0.5128; 0.6154; 0.6923; 0.7436;
                  0.7949; 0.8462; 0.8974; 0.9231; 0.9487; 0.9744; 1">
  <!ENTITY keySplines "0 .75 .5 1; .5 0 1 .25; 0 .25 .25 1; .5 0 1 .5;
                       0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1;
                       0 0 1 1; 0 0 1 1; 0 0 1 1">
  <!ENTITY calcMode "spline">
  <!ENTITY begin "mouseover">
]>

<svg width="665px" height="250px" viewBox="0 0 665 250"
     xml:space="preserve">

  <!-- <title>, <defs> et fond <rect> comme nous l'avons déjà vu -->

  <g id="cubes" transform="translate(300.25, 143.45)" >
    <use xlink:href="#cube" transform="translate(0,-72)">
      <animate dur="&dur;" values="&values;" keyTimes="&keyTimes;"
               keySplines="&keySplines;"
               attributeName="y" begin="&begin;"
               restart="whenNotActive" calcMode="&calcMode;" />
    </use>
    <!-- quinze autres <use> -->
  </g>

</svg>

[Voir le code SVG]

Et voilà ! Cela ressemble un peu à du rafistolage, mais cela marche assez bien. Maintenant, si nous décidons de changer le “keySplines” pour le troisième intervalle de notre animation, nous devons l’éditer qu’une seule fois. Autrement, pour ce qui est de l’animation, nous avons terminé. Elle devrait ressembler de très près à la version originale en SWF. En fait, sur mon ordinateur portable, l’animation exécutée par le module d’affichage SVG d’Adobe est beaucoup plus fluide que le SWF exécuté par Flash. De plus, la version gzipée (plus connue sous le terme SVGZ) de l’animation finale occupe seulement 926 octets, contre 1,29 Ko pour la version SWF. Plus élégant et plus petit !

Conclusion

J’espère que vous avez apprécié le petit tour de quelques unes des caractéristiques les plus intéressantes de l’animation SVG. Le domaine de l’animation SVG est vaste, spécialement au sujet de la synchronisation, à laquelle nous nous intéresserons dans de prochains articles. Je pense que cette simple animation met en évidence quelques concepts clés de l’animation SVG, principalement qu’elle est basée sur le temps et sur les propriétés, ainsi que quelques différences par rapport aux possibilités offertes par l’animation SWF.

Il est probablement temps pour vous de lire le chapitre sur l’animation des spécifications SVG 1.0 et de creuser l’affaire de vous-même. Ce qui vous manquera le plus est un outil d’édition pour animations SVG. WebDraw 1.0 de Jasc vient juste d’être annoncé et inclut le support de quelques éléments de la technologie SVG. De plus Adobe a récemment demandé des retours d’informations sur la liste développeurs SVG sur le besoin d’un support de SVG dans leur outil d’animation LiveMotion. Adobe vous propose d’envoyer vos différents besoins ici. Si vous souhaitez que SVG se développe en utilisation et simplicité de développement, faites-vous entendre d’Adobe et d’autres sociétés.

Textes originaux en anglais sur O’Reilly : Digging Animation par Antoine Quint

opoppon Développement Web , ,

  1. Pas encore de commentaire
  1. Pas encore de trackbacks
Vous devez être identifié pour poster un commentaire