Tutoriel SVG/SMIL animations interactives
<pageby nominor="false" comments="false"/>
Cet article est une ébauche à compléter. Une ébauche est une entrée ayant un contenu (très) maigre et qui a donc besoin d'un auteur.
Interactivité avec SVG
Prérequis:
Principe et gestion des événements
L’interactivité est donc la gestion des événements qui ressemblent au principe des GUI (aussi nommée interface graphique) modernes (par exemple en JavaScript ou ActionScript) et elle est conforme à la spécification DOM2 (document object model).
Types d’interactivité:
- Des actions initiées par l'utilisateur, telle que presser le bouton d'une souris, peuvent causer l'exécution d'animations ou de scripts;
- L'utilisateur peut initier des hyperliens vers de nouvelles pages Web par des actions (par ex. cliquer sur un élément)
- L'utilisateur peut zoomer dans un contenu SVG ou effectuer un panoramique autour de celui-ci (dépend du client).
- Les déplacements par l'utilisateur du dispositif de pointage peuvent modifier le curseur qui indique sa position
L’essentiel, SVG comprend
- des attributs d'événements (ex. onclick="hello()" ) pour lancer des scripts
- des noms d’ événements qu’on peut insérer dans certains attributs (par ex: begin="click" ) et qui définissent l’élément d’animation à déclencher quand un événement donné survient.
Evénements SVG/SMIL
La spécification SVG1 définit plus de 20 événements. Les plus importants peuvent être capturés par des "attributs d’événements" qu’on insère dans les balises qu’on veut rendre interactives.
Il existe certains événements sans attributs qui concernent la modification de l’arbre DOM. En plus, à l'aide du Modèle Objet de Document (DOM) de SVG, un script peut enregistrer des guetteurs d'événements (event handlers) DOM2 de manière à ce qu'un script puisse être invoqué quand un événement donné survient.
Un résumé des noms et attributs d’événement
Le nom de l’événement sera utilisé pour identifier un event dans des balises d’animation (comme "begin").
<animateColor fill="freeze" dur="0.1s" to="blue" from="yellow"
attributeName="fill" begin="mouseover"/>
L’attribut d’événement permet de placer des "guetteurs d’événement"
<circle onmouseover="circle_click(evt)" cx="300" cy="225" r="100" fill="red"/>
Donc attention : Ne confondez pas nom d’événement à utiliser dans les attributs des éléments d’animation et attributs d’événements pour lancer des scripts !!
"mouseover" pas égal à "onmouseover" (.... ou vous perdrez qq. heures ...)
La table suivante réunit la définition de quelques éléments et attributs associés
Nom de |
Description: un événement survient quand ... |
Attribut |
---|---|---|
focusin |
un élément reçoit l'attention (le focus), par ex. l’élément 'text' devient sélectionné. |
onfocusin |
focusout |
un élément perd l'attention, (désélection). |
onfocusout |
activate |
un élément est activé, par exemple, au travers d'un clic de souris ou l'appui d'une touche.
|
onactivate |
click |
le bouton du dispositif de pointage (souris, touchpad, stylo etc.) est cliqué au-dessus d'un élément.
|
onclick |
mousedown |
le bouton de pointage est pressé au-dessus d'un élément. |
onmousedown |
mouseup |
le bouton de pointage est relâché au-dessus d'un élément. |
onmouseup |
mouseover |
le dispositif de pointage est déplacé sur un élément. |
onmouseover |
mousemove |
le dispositif de pointage est déplacé alors qu'il est au-dessus d'un élément.. |
onmousemove |
mouseout |
le dispositif de pointage (souris) est écarté de l’élément. |
onmouseout |
SVGLoad |
le client a complètement interprété l'élément et ses descendants
|
onload |
SVGUnload |
le client enlève le document SVG (élément svg le plus externe) |
onunload |
SVGAbort |
le chargement de la page est interrompu avant qu'un élément ait pu être complètement chargé. |
onabort |
SVGError |
un élément ne se charge pas correctement ou quand une erreur survient lors de l'exécution d'un script. |
onerror |
SVGResize |
une vue de document (svg le plus externe) est redimensionnée. |
onresize |
SVGScroll |
une vue du document est glissée sur X, sur Y ou les deux. |
onscroll |
SVGZoom |
le document change de niveau de zoom lors d'une interaction avec l'utilisateur. (éléments 'svg' les plus externes). |
onzoom |
beginEvent |
un élément d'animation commence.
|
onbegin |
endEvent |
un élément d'animation s'achève (voir TimeEvent) |
onend |
repeatEvent |
un élément d'animation se répète.
|
onrepeat |
Exemples
Simples mouse click et mouse over
L'animation de type SVG-SMIL permet d'utiliser les événements de façon très simple
Quelque chose comme Button.click
permet de se référer au click sur un élément qui a un id=Button
et de lancer une animation
Voici une illustration:
<svg style="margin-left:50px;border:1px solid blue" height="300" width="300"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
<g id="Button"
transform="translate(100,100)">
<ellipse stroke-width="2" stroke="none" fill="yellow" ry="1cm" rx="2cm" >
<animate fill="freeze" dur="1s" begin="Button.click" from="1cm" to="5cm" attributeName="ry"/>
<animate fill="freeze" dur="1s" begin="Button.click" from="2cm" to="10cm" attributeName="rx"/>
</ellipse>
<text style="font-family:Arial;font-size:18;" alignment-baseline="middle" x="-1cm">Click me !</text>
</g>
</svg>
Code source (avec variantes)
- http://tecfa.unige.ch/guides/svg/ex/mouse-over/simple-click.html
- http://tecfa.unige.ch/guides/svg/ex/mouse-over/simple-click2.html (Animation elements outside the animated element)
- http://tecfa.unige.ch/guides/svg/ex/mouse-over/simple-click3.html (Animation happens in another element)
Lancer une animation de mouvement:
- http://tecfa.unige.ch/guides/svg/ex/smil-dom/drive-start.svg (Pure SVG)
- http://tecfa.unige.ch/guides/svg/ex/smil-dom/drive-start.html (HTML5 + SVG)
Cet exemple montrent comment inclure un dessin compliqué avec un élément svg qui remet les coordonnées de l'objet à animer à 0/0. Si vous ne faites pas cela, vous allez en baver avec un dessin compliqué ...
Example Mouse over/out
<?xml version="1.0" ?>
<svg height="200" width="500"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
<ellipse stroke-width="2" stroke="black" fill="yellow"
cx="3cm" cy="2cm" ry="1cm" rx="2cm">
<animate fill="freeze" dur="0.1s" to="blue" from="yellow"
attributeName="fill" begin="mouseover"/>
<animate fill="freeze" dur="0.1s" to="yellow" from="blue"
attributeName="fill" begin="mouseout"/>
</ellipse>
</svg>
Live example / source code:
Animation avec un événement mouseover
On va d'abord examiner quelques fragments du code avant de montrer le tout.
(1) Un lien vers un autre URL se met simplement autour de l'élément cliquable
<a xlink:href="http://tecfa.unige.ch">
<rect style="fill:#00FF00;stroke:#00FF00" width="200"
height="26" ry="5" rx="5" y="100" x="100"/>
</a>
(2) L’ellipse jaune qui contient un texte va activer une animation (changement de couleur) lorsqu’on glisse la souris dessus ou lorsqu’on la sort de nouveau (l’attribut "begin" va s’activer lorsqu’il y a un mouseover ou un mouseout).
<g transform="translate(100,100)">
<ellipse stroke-width="2" stroke="black" fill="yellow" ry="1cm" rx="2cm"
id="hint_button">
<animateColor fill="freeze" dur="0.1s" to="blue" from="yellow"
attributeName="fill" begin="mouseover"/>
<animateColor fill="freeze" dur="0.1s" to="yellow" from="blue"
attributeName="fill" begin="mouseout"/>
</ellipse>
<text style="font-size:12;" alignment-baseline="middle" x="-1cm">Touch me !</text>
</g>
(3) Ensuite, on a un contenu caché et qui s’affiche lorsque l'élément qui a l'id "hint_button " rencontre un évément mouseover. Autrement dit: l'attribut "begin" d'une animation ne peut pas seulement être un temps, un événement de l'élément parent comme ci-dessus, mais également un événement qui a lieu dans un autre élément (l'ellipse dans notre cas anime la propriété style du cercle caché)!!
<g transform="translate(100,200)" style="display:none">
<circle style="fill:yellow;" r="2cm" cy="1cm" cx="1cm"/>
<text style="font-size:12;" alignment-baseline="middle" x="-0.8cm" y="1cm">
Find the scecret URL !</text>
<animate fill="freeze" dur="0.1s" begin="hint_button.mouseover"
from="none" to="block" attributeName="display"/>
<animate fill="freeze" dur="0.1s" begin="hint_button.mouseout"
from="block" to="none" attributeName="display"/>
</g>
Voici l'exemple complet:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg height="900" width="900"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
<desc>Un lien se me simplement autour de l'élément qui fait
"hint_button"</desc>
<a xlink:href="http://tecfa.unige.ch">
<rect style="fill:#00FF00;stroke:#00FF00" width="200"
height="26" ry="5" rx="5" y="100" x="100"/>
</a>
<desc>Ici on implémente un hint_button avec une ellipse qui contient
un texte. Les éléments d'animation sont placés à l'intérieur d'une
éllipse. L'animation (un changement de couleur) va s'activer
lorsqu'il y a un mouseover (l'attribut "begin" va s'activer). Note:
un événement mouseover aura un deuxième effet. L'identificateur
"hint_button" se retrouve dans les éléments d'animations ci-après
(le circle) et va aussi déclencher une action</desc>
<desc>This bouton will change color when mouseover, back to original
when the mouse moves out. Notice the hint_button id which we will
use later.</desc>
<g transform="translate(100,100)">
<ellipse stroke-width="2" stroke="black" fill="yellow"
ry="1cm" rx="2cm" id="hint_button">
<animateColor fill="freeze" dur="0.1s" to="blue" from="yellow"
attributeName="fill" begin="mouseover"/>
<animateColor fill="freeze" dur="0.1s" to="yellow" from="blue"
attributeName="fill" begin="mouseout"/>
</ellipse>
<text style="font-size:12;" alignment-baseline="middle" x="-1cm">Touch me !</text>
</g>
<desc>Ici on a un contenu caché et qui se déclenche (affiche)
lorsque l'élément qui a l'id "hint_button" a un mouseover. Autrement
dit: l'attribut "begin" d'une animation ne peut pas seulement être
un temps, un événement de l'élément parent comme ci-dessus, mais
également un événement qui a lieu dans un autre élément (l'ellipse
dans notre cas)!! </desc> <desc> This is a hidden content that will
appear on mouseover of the element that has id=hint_button that we
defined above.</desc>
<g transform="translate(100,200)" style="display:none">
<circle style="fill:yellow;" r="2cm" cy="1cm" cx="1cm"/>
<text style="font-size:12;" alignment-baseline="middle" x="-0.8cm" y="1cm">
Find the scecret URL !</text>
<animate fill="freeze" dur="0.1s" begin="hint_button.mouseover"
from="none" to="block" attributeName="display"/>
<animate fill="freeze" dur="0.1s" begin="hint_button.mouseout"
from="block" to="none" attributeName="display"/>
</g>
</svg>
Interaction mouse click et animation invisible/visible
L'objectif ici est de créer une page HTML5 avec un contenu, où lorsque l’utilisateur clique sur un bouton, cela fait apparaître un objet.
- Aller sur svg-editor
Créer une forme qui sera la base d'un bouton. Le nom du dessin est donné automatiquement (svg_1), pour plus de facilité par la suite et pour pouvoir se retrouver dans le code, je le renomme btn_ovale.
- Créer le texte du bouton. Nommé automatiquement svg_2, je le renomme btn_txt
- Grouper les deux éléments pour en construire un seul. Je le renomme "bouton".
- Créer un élément qui va apparaître lorsqu'on clique sur le bouton. J'ai créé un rectangle composé de 2 rectangles groupés et je l'ai nommé "rectangles".
- Cliquer sur l'icône svg, cela donne le code des dessins réalisés.
- Créer une page HTML5. Pour ce faire, je me suis basée sur le code suivant, trouvé ici
<!DOCTYPE html>
<html>
<head>
<title>HTML5 SVG demo</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<h1>HTML5 SVG Demo</h1>
A nice green circle:
<svg id="circle" height="200" xmlns="http://www.w3.org/2000/svg">
<circle id="greencircle" cx="30" cy="30" r="30" fill="green" />
</svg>
<hr>
<address>Created by DKS. This is free code</address>
</html>
Une fois le code collé dans l'éditeur de code source, enregistrer le fichier en format html.
- Copier-coller le code généré par le svg-editor à l'endroit indiqué
- Ajouter le code pour l'interaction/animation aux endroits indiqués
- Si vous testez le fichier dans un validateur htlm, vous verrez des erreurs du type : "Bad value null for attribute stroke-linejoin on element rect." Il suffit de supprimer les attributs stroke-linejoin et stroke-linecap et les valeurs "null" indiquées par le validateur html. En effet, il semblerait que les attributs stroke-linejoin et stroke-linecap n'acceptent pas la valeur "null".
- Et voilà le résultat
Résumé
- Des animations peuvent se déclencher suite à un geste d’utilisateur.
- Le geste de l’utilisateur crée un événement géré (ici) par les balises "begin".
- Autrement dit, le "begin" fait guetteur d’événement pour l’événement nommé.
- Une animation d’un élément peut se déclencher suite à un événement qui a lieu dans un autre élément (on bouge la souris sur l’ellipse et c’est le cercle qui apparaît)
Interaction SMIL - script
Il existe deux cas de figure:
- Script -> SMIL
- SMIL -> Script
Ci-dessous un simple exemple qui montre comment déclencher un script depuis SVG et ensuite le script qui arrête l'animation avec une simples méthode DOM.
Exemple Pendule
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.0"
viewBox="0 0 300 200">
<script>
function stop () {
document.documentElement.pauseAnimations();
}
function start () {
document.documentElement.unpauseAnimations();
}
</script>
<desc>
The pendulum code was taken from http://www.treebuilder.de/xul/svg2apng/pendel.svg. The pauseAnimations method is documented in the SVG 1.1 spec: http://www.w3.org/TR/SVG/struct.html#__svg__SVGSVGElement__pauseAnimations
</desc>
<g>
<line x1="100" y1="0" x2="100" y2="90" stroke="black"/>
<circle cx="100" cy="90" r="10"/>
<animateTransform attributeName="transform" type="rotate" values="0,100,0;70,100,0;0,100,0;-70,100,0;0,100,0" keySplines="0,0.5,0.5,1;0.5,0,1,0.5;0,0.5,0.5,1;0.5,0,1,0.5" calcMode="spline" begin="0s" dur="4s" repeatCount="indefinite"/>
</g>
<g onclick="stop()" transform="translate(150 0)">
<rect width="50" height="30" rx="10" stroke="black" fill-opacity="0.2"/>
<text id="t" style="font:16px Arial Black;fill:white;stroke:black" transform="translate(5 20)">STOP</text>
</g>
<g onclick="start()" transform="translate(5 0)">
<rect width="50" height="30" rx="10" stroke="black" fill-opacity="0.2"/>
<text id="t" style="font:16px Arial Black;fill:white;stroke:black" transform="translate(2 20)">START</text>
</g>
</svg>
Alternative sans script:
Exemple du pendule détail
L'attibut viewBox indique la grandeur et la hauteur de votre animation
viewBox="0 0 300 200"
Le code JavaScript définit ce que les boutons "stop et Start" vont faire. L'animation (le pendule) va stopper quand on appuie sur le bouton gris "stop" et recommencer quand on appuie sur le bouton "start"
<script>
function stop () {
document.documentElement.pauseAnimations();
}
function start () {
document.documentElement.unpauseAnimations();
}
</script>
Après la définition des fonctions JavaScript dans l'élément </script>, on commence à faire la mise en forme du pendule mais aussi des boutons "stop et start"
Commençons par la ligne le cercle et le mouvement de balancier :
<line x1="100" y1="0" x2="100" y2="90" stroke="black"/><br />
- Cela dit :
que l'on a construit une ligne noire ( stroke) avec certaine mesure : x1="100" y1="0" x2="100" y2="90".
Pour rappel :
- x1 : spécifie la position du premier point sur l'axe des abscisses ;
- x2 : spécifie la position du second point sur l'axe des abscisses ;
- y1 : spécifie la position du premier sur l'axe des ordonnées ;
- y2 : spécifie la position du second point sur l'axe des ordonnées ;
<circle cx="100" cy="90" r="10"/><br />
Cela dit que l'on a construit un cercle avec certaine mesure : cx="100" cy="90" r="10"
Pour rappel :
- L'attribut r spécifie le rayon du cercle, et les attributs cx et cy les coordonnées du centre.
- Maintenant il s'agit d'animer le pendule :
<animateTransform attributeName="transform" type="rotate"
values="0,100,0;70,100,0;0,100,0;-70,100,0;0,100,0"
keySplines="0,0.5,0.5,1;0.5,0,1,0.5;0,0.5,0.5,1;0.5,0,1,0.5"
calcMode="spline" begin="0s" dur="4s" repeatCount="indefinite"/><br />
- La première partie dit que c'est : un élément qui va bouger et cela donne les valeurs, le type et le mode ce calcul.
- La deuxième partie va dire :
Que l'élément qui va bouger :
- Va commencer à : "o" :begin="0s"
- qu'il va durer 4 seconde : dur="4s"
- qu'il va toujours se répéter : "indefinite"
Maintenant tout est dit pour le pendule et on ferme la balise </g>.
On va s’intéresser au bouton start et stop.
Nous allons détaillé le bouton "stop" car l'autre ( start) est basé le même principe ( on a ouvert de nouvelle balise <g>).
<g>
<g onclick="stop()" transform="translate(150 0)">
<rect width="50" height="30" rx="10" stroke="black" fill-opacity="0.2"/>
<text id="t" style="font:16px Arial Black;fill:white;stroke:black" transform="translate(5 20)">STOP</text>
</g>
<g onclick="stop()" transform="translate(150 0)">
- On réfère ici à la function que l'on a défini plus en amont dans la page:
function stop () {
document.documentElement.pauseAnimations();
On dit juste que ce bouton devra "fonctionner" avec onclick. C'est-à-dire : arrêter le mouvement du pendulier( vous pouvez aller voir les possibilités en amont dans le tableau). On aurait pu aussi le faire en faisant passer la souris juste dessus les boutons pour stopper le mouvement).
- Ensuite : il faut dire où l'on veut dans l'espace le bouton avec : transform="translate(150 0)"
- On donne la forme et l'opacité au rectangle : <rect width="50" height="30" rx="10" stroke="black" fill-opacity="0.2"/>
- Maintenant on utilise le <text..</text> et on lui donne son style. Cela correspond au "stop" écrit dans le bouton gris.
On fait de même avec le bouton "start" et on referme la balise </g>, ainsi que la balise finale : </svg>
- Et voilà, vous n'avez plus qu'à aller à nouveau observer le modèle en fonction.