« Tutoriel SVG dynamique avec DOM » : différence entre les versions

De EduTech Wiki
Aller à la navigation Aller à la recherche
m (Remplacement de texte — « <pageby nominor="false" comments="false"/> » par « <!-- <pageby nominor="false" comments="false"/> --> »)
 
(22 versions intermédiaires par 8 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
{{stub}}
{{Ebauche}}
{{en construction}}
 
<pageby nominor="false" comments="false"/>
<!-- <pageby nominor="false" comments="false"/> -->
 
'''Avertissement''': Il faudrait complètement revoir ce texte. Il a été écrit il y a longtemps quand les navigateurs implémentaient mal SVG - [[Utilisateur:Daniel K. Schneider|Daniel K. Schneider]] 26 mars 2011 à 15:55 (CET)
 
Consultez plutôt:
* http://www.w3.org/Graphics/SVG/IG/resources/svgprimer.html (enfin même ce document semi-officiel n'est pas à jour pour HTML5)


== Introduction ==
== Introduction ==
Ligne 8 : Ligne 13 :


Certains types d’interactions peuvent se programmer sans savoir grand chose de la programmation DOM (c’est pareil pour le traitement de formulaires HTML avec Javascript ...)
Certains types d’interactions peuvent se programmer sans savoir grand chose de la programmation DOM (c’est pareil pour le traitement de formulaires HTML avec Javascript ...)
Etat de la technologie début 2011. SVG stand-alone ou SVG dans XHTML:
* marche avec Firefox, Opéra, Chrome, Safari (?)
* marchera avec IE9 Béta (?)
Pour HTML 5, consultez [http://caniuse.com/svg-html5 Inline SVG in HTML5].
* Chrome 10 ou 11 semblent le mieux marcher


Voici le principe:
Voici le principe:
Ligne 22 : Ligne 34 :
     var circle = evt.target;
     var circle = evt.target;
     var currentRadius = circle.getAttribute("r");
     var currentRadius = circle.getAttribute("r");
  }
</source>
</source>


Ligne 40 : Ligne 53 :
<svg width="6cm" height="5cm" viewBox="0 0 600 500"
<svg width="6cm" height="5cm" viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg">
     xmlns="http://www.w3.org/2000/svg">
   <desc>Exemple script01 - invoque une fonction ECMAScript a partir d'un evenement onclick
   <desc>Exemple script01 - invoque une fonction ECMAScript  
  </desc>
        a partir d'un evenement onclick </desc>
 
   <!-- Fonction ECMAScript qui change le rayon a chaque clic -->
   <!-- Fonction ECMAScript qui change le rayon a chaque clic -->
   <script type="text/ecmascript"> <![CDATA[
   <script type="text/ecmascript"> <![CDATA[
     function circle_click(evt) {
     function circle_click(evt) {
Ligne 71 : Ligne 86 :


* L’exemple implémente un switch (assimilable à un interrupteur de lumière)
* L’exemple implémente un switch (assimilable à un interrupteur de lumière)
* On ajoute à la définition cerle un event-handler. Autrement dit: en cliquant sur le cercle (événement = "onclick"), la fonction circle_click ("event handler") va être activée avec l'argument "evt"
* On ajoute à la définition cercle un event-handler. Autrement dit: en cliquant sur le cercle (événement = "onclick"), la fonction circle_click ("event handler") va être activée avec l'argument "evt"


  <circle onclick="circle_click(evt)
  <circle onclick="circle_click(evt)
Ligne 77 : Ligne 92 :


* La fonction ''circle_click'' qu’on a défini va recevoir comme argument un objet événement ( le paramètre '' evt'' )
* La fonction ''circle_click'' qu’on a défini va recevoir comme argument un objet événement ( le paramètre '' evt'' )
* L’objet evt sait quel objet a été touché par l’événement. Autrement dit, ''ev.target'' contient l’objet DOM du cercle et on l’assigne à la variable ''circle'' .
* L’objet evt sait quel objet a été touché par l’événement. Autrement dit, ''evt.target'' contient l’objet DOM du cercle et on l’assigne à la variable ''circle'' .


<source lang="javascript">
<source lang="javascript">
  function circle_click(evt) {
  function circle_click(evt) {
     var circle = evt.target:
     var circle = evt.target;
     .....
     .....
   }
   }
Ligne 108 : Ligne 123 :
=== Placement et initialisation du script ===
=== Placement et initialisation du script ===


Le script doit se trouver dans une section CDATA du code SVG, comme en XHTML. La raison est simple: Pour que le XML soit bien formée, on peut ne peut pas y inclure des éléments utilisant une autre syntaxe.
Le script doit se trouver dans une section CDATA du code SVG, comme en XHTML. La raison est simple: pour que le XML soit bien formée, on peut ne peut pas y inclure des éléments utilisant une autre syntaxe.


<source lang="javascript">
<source lang="javascript">
Ligne 119 : Ligne 134 :
</source>
</source>


Un script travaille souvent avec des variables globales et il faut faire de sorte à ce que l’initialisation soit faite lorsque l’utilisateur interagit avec la scène.
Un script travaille souvent avec des variables globales et il faut faire de sorte à ce que l’initialisation soit déjà faite lorsque l’utilisateur interagit avec la scène.


Il faut explicitement charger une fonction d’initialisation. Voici ma façon de faire:
Voici une façon de faire:


<source lang="xml">
<svg  
<svg  
   <script type="text/ecmascript"> <![CDATA[
   <script type="text/ecmascript"> <![CDATA[
Ligne 128 : Ligne 144 :
   var svgdoc, eye_right, ...... ;
   var svgdoc, eye_right, ...... ;


function init (big_bang) {
    function init (big_bang) {
     svgdoc =   big_bang.target.ownerDocument;         // instance of the document
     svgdoc = big_bang.target.ownerDocument; // instance of the document
     .....  }
     .....  }
<svg onload="init(evt)">
<svg onload="init(evt)">
Ligne 135 : Ligne 151 :
   </svg>
   </svg>
</svg>  
</svg>  
</source>


L’élément svg imbriqué déclenche le script init() lorsqu’il est chargé
L’élément svg imbriqué déclenche le script init() lorsqu’il est chargé
Une autre façon est la suivante:
<source lang="xml">
<svg width="4cm" height="2cm" viewBox="0 0 400 200"
    xmlns="http://www.w3.org/2000/svg"
    onload="DebuterAnimation(evt)" >
  <script type="text/ecmascript"><![CDATA[
    function DebuterAnimation(evt) {
      racine = evt.target.ownerDocument;
    }
    function XXX {
    }
  </script>
<rect .... />
</svg>
</source>


=== Le déboggage ===
=== Le déboggage ===


Comme actuellement les clients n’ont pas de console sophistiquée, il faut trouver soi-même la source des problèmes .... ceci dit, les nouvelles versions des navigateurs sont mieux faites... (à vérifier, DKS - 22 mars 2011 à 18:27 (CET)).
Si vous le souhaitez vous pouvez utiliser des outils comme [http://edutechwiki.unige.ch/fr/FireBug#Extension_FireBug_Pour_FireFox [FireBug]]  pour débugger votre script. Sinon quelques autres solutions sont présentées ci-dessous.


Une solution est de semer partout dans votre code des "alert" qui produisent des fenêtres pop-up lorsque la ligne est exécutée.
Une solution est de semer partout dans votre code des "alert" qui produisent des fenêtres pop-up lorsque la ligne est exécutée.
Ligne 174 : Ligne 210 :
==== L’interface SVGDocument ====
==== L’interface SVGDocument ====


* un objet SVGDocument va exister quand l'élément racine de la hiérarchie du document XML est un élément 'svg' (cela correspond à HTMLDocument)
Un objet de type '''SVGDocument''' va exister quand l'élément racine de la hiérarchie du document XML est un élément 'svg' (cela correspond à HTMLDocument)
* On peut l’utiliser pour chercher des éléments par leur id par exemple.
On peut utiliser cet interface pour chercher des éléments par leur id par exemple.


<source lang="javascript">
<source lang="javascript">
  svgdoc = big_bang.target.ownerDocument;// instance of the document
  svgdoc = big_bang.target.ownerDocument; // instance of the document
  eye_right = svgdoc.getElementById ("eyeRightId"); // getElementById()
  eye_right = svgdoc.getElementById ("eyeRightId"); // getElementById()
</source>
</source>


* Attention: Si votre SVG est imbriqué dans un autre document XML (XHTML par exemple) cet objet n’existera pas ! Par contre, cela marche en HTML5.
Attention: Si votre SVG est imbriqué dans un autre document XML (XHTML par exemple) cet objet n’existera pas !
 


====L'interface SVGSVGElement====
====L'interface SVGSVGElement====
Ligne 189 : Ligne 224 :
* SVGSVGElement est l'interface pour l'élément 'svg'. Cette interface contient des méthodes utilitaires variées diverses couramment employées, telles que des opérations matricielles et la capacité de contrôler le moment du ré-affichage sur les appareils de rendu visuel....
* SVGSVGElement est l'interface pour l'élément 'svg'. Cette interface contient des méthodes utilitaires variées diverses couramment employées, telles que des opérations matricielles et la capacité de contrôler le moment du ré-affichage sur les appareils de rendu visuel....


 
==== Eléments utiles du XML DOM2 ====
 
====D. Eléments utiles du XML DOM2====
 
 


=====L'interface Document=====
=====L'interface Document=====


* L'interface Document représente le document XML entier. Donc soit le document SVG standalone ou encore le document XML ou HTML dans lequel SVG est imbriqué
L'interface Document représente le document XML entier. Donc soit le document SVG standalone ou encore le document XML ou HTML dans lequel SVG est imbriqué
* Voir aussi: [svg-dyn.htm#62986 C. “Classes et méthodes SVG DOM et XML DOM 2” [32]]
* Voir aussi: '' http://tecfa.unige.ch/guides/tie/html/php-xml/php-xml.html''
 
 


=====L'interface Node=====
=====L'interface Node=====


* L'interface Node est le type de données principal pour tous les modèles DOM. Il représente un seul nœud dans l'arbre du document
L'interface Node est le type de données principal pour tous les modèles DOM. Il représente un seul nœud dans l'arbre du document
* Le plupart des classes implémentent la plupart des méthodes (cela veut dire que pour manipuler un élément SVG, vous pouvez utiliser des méthodes "Node").
* Le plupart des classes implémentent la plupart des méthodes (cela veut dire que pour manipuler un élément SVG, vous pouvez utiliser des méthodes "Node").
* Ainsi, les attributs '' nodeName'' , '' nodeValue'' et '' attributes'' forment un mécanisme pour obtenir une information sur un nœud, sans devoir faire appel à des interfaces dérivées spécifiques. (voir exemple suivant)
* Ainsi, les attributs '' nodeName'' , '' nodeValue'' et '' attributes'' forment un mécanisme pour obtenir une information sur un nœud, sans devoir faire appel à des interfaces dérivées spécifiques. (voir exemple suivant)
* Sinon, il existe plein de méthodes pour connaître et manipuler les enfants.
* Sinon, il existe plein de méthodes pour connaître et manipuler les enfants.
=====L'interface Element=====
=====L'interface Element=====


* L'interface Element représente un élément dans un document XML. Les éléments peuvent avoir des attributs associés.
* L'interface Element représente un élément dans un document XML. Les éléments peuvent avoir des attributs associés.


===== getAttribute ("string")=====


Ramène une valeur d'attribut par son nom


========
element = ... // objet qui représente un élément
element.''getAttribute("r")''


===== setAttribute ("name", "value")=====


Ajoute un nouvel attribut. Si un attribut avec ce nom est déjà présent dans l'élément, sa valeur est changée pour celle du paramètre value. Exemples d'application :
element.setAttribute ("fill", "yellow");
element.setAttribute ("font-weight","bold");
element.setAttribute ("stroke-width", "25.5px");


========
=====getElementById ("id")=====
 
 
 
====getAttribute ("string")====
 
* Ramène une valeur d'attribut par son nom


element = ... // objet qui représente un élément
Retourne l’élément dont l'ID est donné par l'attribut elementId. Si un tel élément n'existe pas, cela retourne null.


element.'' getAttribute("r")''
Il s'agit ici d'une méthode très importante pour réaliser facilement des animations, car elle vous permet d’identifier facilement n’importe quel élément enfant qui a un identificateur (attribut "id").
eye_right = svgdoc.getElementById("eyeRightId");


======L’interface Event======


 
permet de fournir des informations sur un événement, par ex. l’attribut target
====setAttribute ("name", "value")====
 
* Ajoute un nouvel attribut. Si un attribut avec ce nom est déjà présent dans l'élément, sa valeur est changée pour celle du paramètre value
 
element.'' setAttribute'' ("fill", "yellow");
 
 
 
====getElementById ("id")====
 
* Retourne l’élément dont l'ID est donné par l'attribut elementId. Si un tel élément n'existe pas, cela retourne null.
* Méthode très importante pour les animations, car elle vous permet d’identifier facilement n’importe quel élément enfant qui a un identificateur (attribut "id").
* Voir [svg-dyn.htm#16360 Exemple 4-3: “Simple interaction avec DOM” [36]]
 
eye_right = svgdoc.getElementById("eyeRightId");
 
 
 
=====L’interface Event=====
 
* permet de fournir des informations sur un événement, par ex. l’attribut target


  function infos(evt) {
  function infos(evt) {
var element = '' evt.target'' ; .... }
<circle '' onclick="infos(evt)"'' .... />


var element = '' evt.target'' ; .... }
====Exemple DOM alert====


<circle '' onclick="infos(evt)"'' .... />
Montre quelques méthodes DOM simples
* http://tecfa.unige.ch/guides/svg/ex/svg-dom/dom-alert.svg'' (animation)
* http://tecfa.unige.ch/guides/svg/ex/svg-dom/


<source lang="xml">
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="7cm" height="6cm" viewBox="0 0 600 500"
    xmlns="http://www.w3.org/2000/svg">
  <desc>Exemple qui affiche des alert suite à un evenement onclick
  </desc>


  <script type="text/ecmascript"> <![CDATA[
    function infos(evt) {
      var element = evt.target;
      el_name = element.nodeName;
      el_attributes = element.attributes;
      circle_size = element.getAttribute("r")
      display_text = "Element name = " + el_name;
      display_text += " \nAttributes = " + el_attributes;
      display_text += " \nCircle size = " + circle_size;
      alert(display_text);
      element.setAttribute("fill", "yellow");
    }
  ]]> </script>


====Exemple 4-2: DOM alert====
  <!-- S'execute a chaque clic -->
  <circle onclick="infos(evt)" cx="300" cy="225" r="100" fill="red"/>


* montre quelques méthodes DOM simples
  <text x="300" y="480"
* '' http://tecfa.unige.ch/guides/svg/ex/svg-dom/dom-alert.svg'' (animation)
        font-family="Verdana" font-size="32" text-anchor="middle">
* '' http://tecfa.unige.ch/guides/svg/ex/svg-dom/''
    Cliquer sur le cercle et lire le popup ...
  </text>
</svg>
</source>
=== Gestionnaire d'événements SVG ===


  <script type="text/ecmascript"> <![CDATA[
Voici quelques-uns des plus importants gestionnaires d'événements SVG: (Pour une liste complète, voir: [http://www.w3.org/TR/SVG11/interact.html#SVGEvents W3C-SPEC])


    function infos(evt) {
* '''onmouseover''': exécuté lorsque le curseur se déplace au-dessus d'un objet
* '''onmouseout''':  exécuté lorsque le curseur quitte un objet
* '''onmousemove''': exécuté lorsque le curseur se déplace sur un objet
* '''onclick''': exécuté quand l'utilisateur clique sur un objet
* '''onload''': déclenché lorsqu'un fichier SVG a été chargé
* '''onzoom''': déclenché après que l'utilisateur change le niveau du zoom, soit par une interaction directe de l'utilisateur ou de tout changement à la propriété currentScale disponible sur l'interface SVGSVGElement.
* '''onscroll''': déclenché lorsque l'utilisateur fait défiler un svg graphiques
* '''onresize''': déclenché lorsqu'un document a été redimensionnée


      var element = ''evt.target''<nowiki>
=== Exemple DOM simple===
; XML DOM</nowiki>


      el_name = ''element.nodeName''<nowiki>
* http://tecfa.unige.ch/guides/svg/ex/svg-dom/omme-dom1.svg'' (animation)
; // XML DOM2</nowiki>
* http://tecfa.unige.ch/guides/svg/ex/svg-dom/omme.svg'' (dessin de départ)
* http://tecfa.unige.ch/guides/svg/ex/svg-dom/''


      el_attributes = ''element.attributes; ''
<source lang="xml">
  // XML DOM2
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Created with Inkscape (http://www.inkscape.org/)
Daniel Schneider @ tecfa.unige.ch (DKS)
  March 2005
Modified some Inkscape output: missing doctype, opacity
Added script and events
-->
<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  height="600.00000" width="800.00000"
  y="0.00000000" x="0.00000000"
  version="1.0">


      circle_size = ''element.getAttribute("r") ''
  <title>Simple Interactivity with Dom</title>
// XML DOM2
  <desc>This is a simple SVG-DOM demo. Clicking on buttons will change the face, i.e. modifiy XML/SMIL attributes. The drawing was made (quickly) with Inkscape. I did not try to change CSS styles, so I made a few manual changes to the original static SVG which is in file omme.svg</desc>
  <defs>
  <script type="text/ecmascript">


      display_text = "Element name = " + el_name;
  <![CDATA[


      display_text += " \nAttributes = " + el_attributes;
  // variables globales qu'on utilise dans les 2 fonctions
  var svgdoc, eye_right, eye_left, mouth_angry, mouth_happy, mouth_sad ;


      display_text += " \nCircle size = " + circle_size;
  // set to 0 in production, 1 for things to debug, 2 for things fixed
  // var debug = 2;
  var debug = 1;


      alert(display_text);
  function init (big_bang) {
 
    svgdoc =    big_bang.target.ownerDocument;          // instance of the document
      element.''setAttribute''
    eye_right = svgdoc.getElementById("eyeRightId");    // getElementById()
("fill", "yellow"); //XML DOM2
    eye_left =  svgdoc.getElementById("eyeLeftId"); 
    if (debug==2) alert("eyeLeftId = " + eye_left);
    mouth_angry = svgdoc.getElementById("angry"); 
    mouth_happy = svgdoc.getElementById("path1363"); 
    mouth_sad  = svgdoc.getElementById("path2168"); 
    if (debug==2) alert ("The document did load nicely, global variables are defined");
  }


    function face_change(eye_color, emotion) {
    eye_left.setAttribute("fill", eye_color);
    eye_right.setAttribute("fill", eye_color);
    if (debug==2) alert ("mouth emotion =" + emotion);
    switch (emotion) {
    case mouth_angry:
mouth_angry.setAttribute ("visibility","visible");
mouth_happy.setAttribute ("visibility","hidden");
mouth_sad.setAttribute ("visibility","hidden");
break;
    case mouth_happy:
mouth_angry.setAttribute ("visibility","hidden");
mouth_happy.setAttribute ("visibility","visible");
mouth_sad.setAttribute ("visibility","hidden");
break;
    case mouth_sad:
mouth_angry.setAttribute ("visibility","hidden");
mouth_happy.setAttribute ("visibility","hidden");
mouth_sad.setAttribute ("visibility","visible");
break;
     }
     }
    }


  ]]> </script>
    function button_click(evt) {
      var button = evt.target;
      var currentButton = button.getAttribute("id");
      if (debug==2) alert ("button =" + currentButton);
      if (debug==2) alert ("eye_left,style = " + eye_left.getAttribute('style') + " fill = " + eye_left.getAttribute('fill') );
      if (currentButton == "blue_button")  {
        face_change ("blue", mouth_happy );
        }
      else if (currentButton == "rect1333") {
        face_change ("red", mouth_angry);
        }
      else {
        face_change ("black", mouth_sad);
        }
    }


  ]]> </script></defs>
    
    


  <!-- S'exécute a chaque clic -->
  <desc>This inner svg is some hack: onload will not work with the top-level svg. We do need init to work in order to get at the document root (this is not like normal XML it seems).</desc>


  <circle ''onclick="infos(evt)"''
  <svg onload="init(evt)">
  cx="300" cy="225" r="100" fill="red"/>


    <desc>Below is the definition of the head, eyes and mouth </desc>


  <rect
    id="rect1303"
    style="fill:#edca5e;fill-opacity:1.0000000;fill-rule:nonzero;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
    y="314.00000"
    x="177.37018"
    height="188.00000"
    width="122.00000" />


===4.3 Exemple DOM simple===
  <path
    id="path1301"
    style="fill:#edca5e;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-284.0000,-122.0000)"
    d="M 676.00000,319.00000 C 676.00000,400.18586 606.60414,466.00000 521.00000,466.00000 C 435.39586,466.00000 366.00000,400.18586 366.00000,319.00000 C 366.00000,237.81414 435.39586,172.00000 521.00000,172.00000 C 606.60414,172.00000 676.00000,237.81414 676.00000,319.00000 L 676.00000,319.00000 z " />


  <desc>Below we have the 2 eyes. Both are deep green for starters.</desc>


  <path
    id="eyeLeftId"
    fill = "#00ff00"
    style="fill-opacity:1;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-284.0000,-122.0000)"
    d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />


====Exemple 4-3: Simple interaction avec DOM====
  <path
    id="eyeRightId"
    fill = "#00ff00"
    style="fill-opacity:0.75000000;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-153.0000,-125.0000)"
    d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />


* '' http://tecfa.unige.ch/guides/svg/ex/svg-dom/omme-dom1.svg'' (animation)
    <desc>Below we have 3 mouthes</desc>
* '' http://tecfa.unige.ch/guides/svg/ex/svg-dom/omme.svg'' (dessin de départ)
* '' http://tecfa.unige.ch/guides/svg/ex/svg-dom/''


  <path
    id="path1363"
    visibility="visibile"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 154.14365,255.24862 C 154.14365,255.24862 169.06078,300.00000 240.33150,298.34255 C 311.60221,296.68509 326.51934,246.96133 326.51934,246.96133" />
  <path
    id="path2168"
    visibility="hidden"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 150.82873,294.22136 C 150.82873,294.22136 165.74586,249.46998 237.01658,251.12743 C 308.28729,252.78489 323.20442,302.50865 323.20442,302.50865" />
  <path
    id="angry"
    visibility="hidden"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 139.22652,280.11050 L 339.77901,278.45304" />


    <desc>Below are the 3 buttons to the right </desc>


=====Note sur la fabrication du dessin=====
  <rect
    onclick="button_click(evt)"
    id="rect1333"
    style="fill:#ff0000;fill-opacity:1.0000000;stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="197.23756"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
  <rect
    onclick="button_click(evt)"
    id="rect1335"
    style="stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="416.02209"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
  <rect
    onclick="button_click(evt)"
    id="blue_button"
    style="fill:#0000ff;fill-opacity:1.0000000;stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="306.62982"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
</svg>
</svg>
</source>


* Le dessin a été fait avec le logiciel InkScape (qui est un très bon logiciel gratuit qui produit du SVG statique), mais il ne fait pas (encore) du dynamique
'''Note sur la fabrication du dessin''':
* Il fallait faire 2-3 retouches:
** remplacer des éléments CSS par des attributs XML (je ne sais pas comment accéder facilement à un élément CSS dans une longe chaîne via le DOM)
** changer quelques valeurs (opacité, couleurs)
** corriger qq. bugs mineurs
** changer qq. id pour des raisons pédagogiques
* Il faut identifier les id de certains éléments
** Trop souvent ce type de logiciel produit des path (au lieu d’une cercle par ex.), donc on ne s’y retrouve pas dans le code.
** Toutefois, on cliquant sur l’objet dans l’éditeur on peut le voir dans l’arbre DOM dans l’éditeur XML.<br /> Il suffit de noter l’id sur une feuille de papier ou encore de le changer en une valeur intelligible.


Le dessin a été fait avec le logiciel InkScape (qui est un très bon logiciel gratuit qui produit du SVG statique), mais il ne fait pas (encore) du dynamique


Il fallait faire 2-3 retouches:
* remplacer des éléments CSS par des attributs XML (je ne sais pas comment accéder facilement à un élément CSS dans une longe chaîne via le DOM)
* changer quelques valeurs (opacité, couleurs)
* corriger qq. bugs mineurs
* changer qq. id pour des raisons pédagogiques
* Il faut identifier les id de certains éléments
* Trop souvent ce type de logiciel produit des path (au lieu d’une cercle par ex.), donc on ne s’y retrouve pas dans le code.
* Toutefois, on cliquant sur l’objet dans l’éditeur on peut le voir dans l’arbre DOM dans l’éditeur XML.<br /> Il suffit de noter l’id sur une feuille de papier ou encore de le changer en une valeur intelligible.


=====Cet exemple:=====
Cet exemple:
 
* implémente des boutons (à droite) qui changent l’émotion du visage.
* implémente des boutons (à droite) qui changent l’émotion du visage.
* les yeux changent de couleur (on aurait pu faire cela sans DOM)
* les yeux changent de couleur (on aurait pu faire cela sans DOM)
* différentes "bouches" sont cachées/montrées et pour cela il faut un script à mon avis.
* différentes "bouches" sont cachées/montrées et pour cela il faut un script à mon avis.


 
''' Voici quelques éléments du dessin SVG''':
 
=====Voici quelques éléments SVG:=====


* Voici l’oeil gauche produit par Inkscape, vert au départ.
* Voici l’oeil gauche produit par Inkscape, vert au départ.


  <path
  <path
     id="eyeLeftId" fill = "#00ff00"
     id="eyeLeftId" fill = "#00ff00"
     style="fill-opacity:1;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
     style="fill-opacity:1;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
     transform="translate(-284.0000,-122.0000)"
     transform="translate(-284.0000,-122.0000)"
     d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />
     d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />
 


* Voici la bouche "angry", une simple ligne (cachée au départ)
* Voici la bouche "angry", une simple ligne (cachée au départ)
 


  <path
  <path
   id="angry" visibility="hidden"
   id="angry" visibility="hidden"
   style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
   style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
   d="M 139.22652,280.11050 L 339.77901,278.45304" />
   d="M 139.22652,280.11050 L 339.77901,278.45304" />
 
 


* Voici le bouton (rouge) qui déclenche le visage "angry"
* Voici le bouton (rouge) qui déclenche le visage "angry"


  <rect
  <rect
 
     onclick="button_click(evt)"
     ''onclick="button_click(evt)"''
 
     id="rect1333"
     id="rect1333"
     style="fill:#ff0000;fill-opacity:1;stroke-width:14.173228"
     style="fill:#ff0000;fill-opacity:1;stroke-width:14.173228"
     y="197.23756"
     y="197.23756"
     x="474.03317"
     x="474.03317"
     height="79.558014"
     height="79.558014"
     width="77.900551" />
     width="77.900551" />


'''Les event handlers'''


 
Lorsque l’utilisateur clique sur un des rectangles à droite, un script se déclenche
=====Les event handlers=====
 
** lorsque l’utilisateur clique sur un des rectangles à droite, un script se déclenche
 
   ''onclick="button_click(evt)"''
   ''onclick="button_click(evt)"''


 
''' Les variables globales du script '''
 
=====Les variables globales du script=====


   // variables globales qu'on utilise dans les 2 fonctions
   // variables globales qu'on utilise dans les 2 fonctions
   var svgdoc, eye_right, eye_left, mouth_angry, mouth_happy, mouth_sad ;
   var svgdoc, eye_right, eye_left, mouth_angry, mouth_happy, mouth_sad ;


 
La fonction d’initialisation sert à trouver les objets qu’on veut animer:
 
=====La fonction d’initialisation sert à trouver les objets qu’on veut animer=====


  function init (big_bang) {
  function init (big_bang) {
     svgdoc =    big_bang.target.ownerDocument;          // instance of the document
     svgdoc =    big_bang.target.ownerDocument;          // instance of the document
     eye_right = svgdoc.getElementById("eyeRightId");    // getElementById()
     eye_right = svgdoc.getElementById("eyeRightId");    // getElementById()
     eye_left =  svgdoc.getElementById("eyeLeftId");
     eye_left =  svgdoc.getElementById("eyeLeftId");
     mouth_angry = svgdoc.getElementById("angry");
     mouth_angry = svgdoc.getElementById("angry");
     mouth_happy = svgdoc.getElementById("path1363");
     mouth_happy = svgdoc.getElementById("path1363");
     mouth_sad  = svgdoc.getElementById("path2168");
     mouth_sad  = svgdoc.getElementById("path2168");
     }
     }


 
La fonction button_click qui gère les clics de l’utilisateur sur les rectangles:
 
=====La fonction button_click=====
 
* Fonction qui gère les clics des l’utilisateur sur les rectangles


  function button_click(evt) {
  function button_click(evt) {
 
   var button = evt.target;
   var button = ''evt.target;''
 
   var currentButton = button.getAttribute("id");
   var currentButton = button.getAttribute("id");
 
    if (currentButton == "blue_button")  {
 
if (currentButton == "blue_button")  {
 
       face_change ("blue", mouth_happy );
       face_change ("blue", mouth_happy );
       }
       }
   else if (currentButton == "rect1333") {
   else if (currentButton == "rect1333") {
       face_change ("red", mouth_angry);
       face_change ("red", mouth_angry);
       }
       }
   else {
   else {
       face_change ("black", mouth_sad);
       face_change ("black", mouth_sad);
       }  }
       }  }


* La fonction button_click reçoit un objet informatique (le paramètre "evt") qui contient toutes les informations sur le click (et surtout l’objet sur lequel on a cliqué) et qu’on va sauver dans une variable "button" ici.
La fonction button_click reçoit un objet informatique (le paramètre "evt") qui contient toutes les informations sur le click (et surtout l’objet sur lequel on a cliqué) et qu’on va sauver dans une variable "button" ici.


  var button = ''evt.target;''
  var button = ''evt.target;''


** la propriété "target" de l’objet "evt" référence l’objet sur lequel on a cliqué
la propriété "target" de l’objet "evt" référence l’objet sur lequel on a cliqué


  var currentButton = ''button.getAttribute("id")''<nowiki>
  var currentButton = button.getAttribute("id");
;</nowiki>


** ensuite on identifie le nom du bouton sur lequel on a cliqué (on lui demande son "id")
Ensuite on identifie le nom du bouton sur lequel on a cliqué (on lui demande son "id"). En fonction de l’id du bouton (donc 1 des 3 rectangles) on appelle une fonction face_change qui va transformer le visage.
* En fonction de l’id du bouton (donc 1 des 3 rectangles) on appelle une fonction face_change qui va transformer le visage.


  face_change ("black", mouth_sad);
  face_change ("black", mouth_sad);


* Le premier argument donné est une couleur de cheveux (blue, red ou black).
Le premier argument donné est une couleur de cheveux (blue, red ou black).
* Le 2ème est une variable associée à l’objet qu’il faut utiliser pour dessiner la bouche
Le 2ème est une variable associée à l’objet qu’il faut utiliser pour dessiner la bouche


La fonction face_change:


 
<source lang="javascript">
=====La fonction face_change=====
function face_change(eye_color, emotion) {
 
  eye_left.setAttribute("fill", eye_color);
function face_change(eye_color, emotion) {
  eye_right.setAttribute("fill", eye_color);
 
  if (debug==2) alert ("mouth emotion =" + emotion);
  eye_left.''setAttribute''
  switch (emotion) {
("fill", eye_color);
    case mouth_angry:
 
    mouth_angry.setAttribute ("visibility","visible");
  eye_right.setAttribute("fill", eye_color);
    mouth_happy.setAttribute ("visibility","hidden");
 
    mouth_sad.setAttribute ("visibility","hidden");
  if (debug==2) alert ("mouth emotion =" + emotion);
    break;
 
    case mouth_happy:
  ''switch (emotion) {''
    mouth_angry.setAttribute ("visibility","hidden");
 
    mouth_happy.setAttribute ("visibility","visible");
    ''case mouth_angry:''
    mouth_sad.setAttribute ("visibility","hidden");
 
    break;
      ''mouth_angry.setAttribute ("visibility","visible");''
    case mouth_sad:
 
    mouth_angry.setAttribute ("visibility","hidden");
    ''mouth_happy.setAttribute ("visibility","hidden");''
    mouth_happy.setAttribute ("visibility","hidden");
 
    mouth_sad.setAttribute ("visibility","visible");
    mouth_sad.setAttribute ("visibility","hidden");
    break;
 
    break;
 
    case mouth_happy:
 
    mouth_angry.setAttribute ("visibility","hidden");
 
    mouth_happy.setAttribute ("visibility","visible");
 
    mouth_sad.setAttribute ("visibility","hidden");
 
    break;
 
    case mouth_sad:
 
    mouth_angry.setAttribute ("visibility","hidden");
 
    mouth_happy.setAttribute ("visibility","hidden");
 
    mouth_sad.setAttribute ("visibility","visible");
 
    break;
 
      }
 
     }
     }
</source>


* L’instruction switch nous permet en fonction de l’objet "emotion/bouche" transmise de rendre cet objet visible et les autres invisibles
L’instruction switch nous permet en fonction de l’objet "emotion/bouche" transmise de rendre cet objet visible et les autres invisibles.
* Note: au lieu de rendre visible/invisible un objet on aurait aussi pu l’enlever/ajouter de la scène
** Avec une balise "<g>" on peut regrouper des enfants (dessin de la "bouche")
** Ensuite, avec le DOM, on peut en ajouter ou enlever


Ceci dit, au lieu de rendre visible/invisible un objet on aurait aussi pu l’enlever/ajouter de la scène. Avec une balise "<g>" on peut regrouper des enfants (dessin de la "bouche"). Ensuite, avec le DOM, on peut en ajouter ou enlever


== Animation avec le DOM ==


==5. Animation avec le DOM==
Exemple 5-1: Exemple dom01 de la spécification française


* http://www.yoyodesign.org/doc/w3c/svg1/animate.html (home de la traduction française de la spécification SVG 1.0)
* http://tecfa.unige.ch/guides/svg/ex/svg-w3c/dom01.svg
* http://tecfa.unige.ch/guides/svg/ex/svg-w3c/


 
A notre avis, il faut surtout utiliser cette fonctionnalité (au lieu des balises animation de SVG):
====Exemple 5-1: Exemple dom01 de la spécification française====
 
* '' http://www.yoyodesign.org/doc/w3c/svg1/animate.html''<br /> (home de la traduction française de la spécification SVG 1.0)
* '' http://tecfa.unige.ch/guides/svg/ex/svg-w3c/dom01.svg''
* '' http://tecfa.unige.ch/guides/svg/ex/svg-w3c/''
 
 
 
=====A notre avis il faut surtout utiliser cette fonctionnalité (au lieu des balises animation de SVG):=====
 
* lorsque certaines types d’animation et d’interpolation n’existent pas, par exemple un rectangle qui se promène sur l’écran au hasard (on ne connaît pas son chemin)
* lorsque certaines types d’animation et d’interpolation n’existent pas, par exemple un rectangle qui se promène sur l’écran au hasard (on ne connaît pas son chemin)
* lorsqu’on utilise un navigateur de type Firefox qui n’implémente pas encore les animations.
* lorsqu’on utilise un navigateur de type Firefox qui n’implémente pas encore les animations.


(explications à faire)
==Bibliothèques JavaScript==
 


----
Une autre possibilité est de créer, animer et/ou manipuler les éléments SVG à l'aide d'une bibliothèque [[JavaScript]]. Ces bibliothèques mettent à disposition une interface de programmation (API) qui permet d'interagir avec les éléments SVG. Voici deux exemples de bibliothèques :


[none [[Image:next.gif|NEXT]]] -- [../../tie.html TIE]
* [http://raphaeljs.com/ Raphaël] : bibliothèque qui est compatible avec les navigateurs plus anciens
* [http://snapsvg.io/ Snap SVG] : bibliothèque plus moderne, mais compatible avec des versions plus récentes des navigateurs


[[Category: SVG]]
[[Category: SVG]]

Dernière version du 22 août 2016 à 19:49

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.


Avertissement: Il faudrait complètement revoir ce texte. Il a été écrit il y a longtemps quand les navigateurs implémentaient mal SVG - Daniel K. Schneider 26 mars 2011 à 15:55 (CET)

Consultez plutôt:

Introduction

Créer des interactions et animations avec le DOM est plus difficile que SVG dynamique avec SMIL, mais on peut faire ce qu’on veut selon le principe que tous les attributs du DOM sont animables.

Certains types d’interactions peuvent se programmer sans savoir grand chose de la programmation DOM (c’est pareil pour le traitement de formulaires HTML avec Javascript ...)

Etat de la technologie début 2011. SVG stand-alone ou SVG dans XHTML:

  • marche avec Firefox, Opéra, Chrome, Safari (?)
  • marchera avec IE9 Béta (?)

Pour HTML 5, consultez Inline SVG in HTML5.

  • Chrome 10 ou 11 semblent le mieux marcher

Voici le principe:

  • Dans l’élément qui doit déclencher un script on place un attribut d’événement, par exemple onclick (Voir tutoriel SVG dynamique avec SMIL)
  • Cet attribut doit définir un fonction avec un argument
    • le nom d’une fonction ECMAScript, par ex: circle_click et qui sera appelée
    • un argument avec lequel sera transmis un objet événement, par ex. evt

Un objet événement est dynamiquement crée par le client. Il contient des informations variées, par exemple où l’événement a été déclenché etc.

  function circle_click(evt) {
    var circle = evt.target;
    var currentRadius = circle.getAttribute("r");
  }
<circle onclick="circle_click(evt)" cx="300" cy="225" r="100" fill="red"/>

Exemple : Simple switch avec DOM

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="6cm" height="5cm" viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg">
  <desc>Exemple script01 - invoque une fonction ECMAScript 
        a partir d'un evenement onclick </desc>

  <!-- Fonction ECMAScript qui change le rayon a chaque clic -->

  <script type="text/ecmascript"> <![CDATA[
    function circle_click(evt) {
      var circle = evt.target;
      var currentRadius = circle.getAttribute("r");
      if (currentRadius == 100)
        circle.setAttribute("r", currentRadius*2);
      else
        circle.setAttribute("r", currentRadius*0.5);
    }
  ]]> </script>

  <!-- Contour en bleu de l'aire du dessin -->
  <rect x="1" y="1" width="598" height="498" fill="none" stroke="blue"/>

  <!-- S'execute a chaque clic -->
  <circle onclick="circle_click(evt)" cx="300" cy="225" r="100"
          fill="red"/>

  <text x="300" y="480" 
        font-family="Verdana" font-size="32" text-anchor="middle">
    Cliquer sur le cercle change sa taille
  </text>
</svg>

Explications:

  • L’exemple implémente un switch (assimilable à un interrupteur de lumière)
  • On ajoute à la définition cercle un event-handler. Autrement dit: en cliquant sur le cercle (événement = "onclick"), la fonction circle_click ("event handler") va être activée avec l'argument "evt"
<circle onclick="circle_click(evt)
        cx="300" cy="225" r="100" fill="red"/>
  • La fonction circle_click qu’on a défini va recevoir comme argument un objet événement ( le paramètre evt )
  • L’objet evt sait quel objet a été touché par l’événement. Autrement dit, evt.target contient l’objet DOM du cercle et on l’assigne à la variable circle .
 function circle_click(evt) {
    var circle = evt.target;
    .....
  }
  • Ensuite on demande au cercle son attribut "r" (qui définit le radius)
 var currentRadius = circle.''getAttribute("r");

Le code suivant substitue la valeur du "r":

  • si le radius == 100, alors on va l’agrandir
  • sinon, on va le diminuer
if (currentRadius == 100)
    circle.setAttribute("r", currentRadius*2);
else circle.setAttribute("r", currentRadius*0.5);

facile, non ? (ce genre de choses se fait aussi en X3D, en HTML et en VRML)

Introduction au scripting avec DOM

Placement et initialisation du script

Le script doit se trouver dans une section CDATA du code SVG, comme en XHTML. La raison est simple: pour que le XML soit bien formée, on peut ne peut pas y inclure des éléments utilisant une autre syntaxe.

<script type="text/ecmascript"> 
  <![CDATA[
  function circle_click(evt) {
    .....    }
  ]]> 
</script>

Un script travaille souvent avec des variables globales et il faut faire de sorte à ce que l’initialisation soit déjà faite lorsque l’utilisateur interagit avec la scène.

Voici une façon de faire:

<svg 
  <script type="text/ecmascript"> <![CDATA[
  // variables globales qu'on utilise dans toutes les fonctions
  var svgdoc, eye_right, ...... ;

    function init (big_bang) {
    svgdoc =  big_bang.target.ownerDocument;  // instance of the document
     .....  }
<svg onload="init(evt)">
    <desc> Ici on insère la véritable scène SVG </desc>
   </svg>
</svg>

L’élément svg imbriqué déclenche le script init() lorsqu’il est chargé

Une autre façon est la suivante:

<svg width="4cm" height="2cm" viewBox="0 0 400 200"
     xmlns="http://www.w3.org/2000/svg"
     onload="DebuterAnimation(evt)" >

  <script type="text/ecmascript"><![CDATA[
    function DebuterAnimation(evt) {
      racine = evt.target.ownerDocument;
    }
    function XXX {
    }
  </script>

 <rect .... />
</svg>

Le déboggage

Si vous le souhaitez vous pouvez utiliser des outils comme [FireBug] pour débugger votre script. Sinon quelques autres solutions sont présentées ci-dessous.

Une solution est de semer partout dans votre code des "alert" qui produisent des fenêtres pop-up lorsque la ligne est exécutée.

Au lieu de les copier/coller tout le temps on propose la solution suivante:

  • Une variable globale debug qu’on peut mettre à 0, 1 ou 2 selon vos besoin.
  • Si par exemple un problème est résolu, on met le "debug level" à 2. Si debug==1 on ne voit plus l’alert.
// set to 0 in production, 1 for things to debug, 2 for things fixed
var debug = 1;

Voici une du code pour produire les "alert"

 if (debug==2) alert ("The document did load nicely, global variables are defined");
 // affiche un string plus une représentation d’un objet
 if (debug==1) alert ("button =" + currentButton);

... sans ce genre de stratégie vous allez souffrir, car il est facile de mal interpréter les spécifications du DOM ....

Classes et méthodes SVG DOM et XML DOM 2

Une liste complète des classes et méthodes SVG DOM serait monstrueuse, il existe une vingtaine de "chapitres" avec nombreuses classes et méthodes.

Tout SVG est répliqué dans DOM (donc y compris animations et interactivité)

A titre d’exemple, il y a 13 classes DOM spécifiques à la structure du document SVG: SVGDocument, SVGSVGElement, SVGGElement, SVGDefsElement, SVGDescElement, SVGTitleElement, SVGSymbolElement, SVGUseElement, ....

Sinon, SVG implémente DOM2 et nous allons surtout utiliser cela par la suite

L’interface SVGDocument

Un objet de type SVGDocument va exister quand l'élément racine de la hiérarchie du document XML est un élément 'svg' (cela correspond à HTMLDocument) On peut utiliser cet interface pour chercher des éléments par leur id par exemple.

 svgdoc = big_bang.target.ownerDocument; // instance of the document
 eye_right = svgdoc.getElementById ("eyeRightId"); // getElementById()

Attention: Si votre SVG est imbriqué dans un autre document XML (XHTML par exemple) cet objet n’existera pas !

L'interface SVGSVGElement

  • SVGSVGElement est l'interface pour l'élément 'svg'. Cette interface contient des méthodes utilitaires variées diverses couramment employées, telles que des opérations matricielles et la capacité de contrôler le moment du ré-affichage sur les appareils de rendu visuel....

Eléments utiles du XML DOM2

L'interface Document

L'interface Document représente le document XML entier. Donc soit le document SVG standalone ou encore le document XML ou HTML dans lequel SVG est imbriqué

L'interface Node

L'interface Node est le type de données principal pour tous les modèles DOM. Il représente un seul nœud dans l'arbre du document

  • Le plupart des classes implémentent la plupart des méthodes (cela veut dire que pour manipuler un élément SVG, vous pouvez utiliser des méthodes "Node").
  • Ainsi, les attributs nodeName , nodeValue et attributes forment un mécanisme pour obtenir une information sur un nœud, sans devoir faire appel à des interfaces dérivées spécifiques. (voir exemple suivant)
  • Sinon, il existe plein de méthodes pour connaître et manipuler les enfants.
L'interface Element
  • L'interface Element représente un élément dans un document XML. Les éléments peuvent avoir des attributs associés.
getAttribute ("string")

Ramène une valeur d'attribut par son nom

element = ... // objet qui représente un élément
element.getAttribute("r")
setAttribute ("name", "value")

Ajoute un nouvel attribut. Si un attribut avec ce nom est déjà présent dans l'élément, sa valeur est changée pour celle du paramètre value. Exemples d'application :

element.setAttribute ("fill", "yellow");
element.setAttribute ("font-weight","bold");
element.setAttribute ("stroke-width", "25.5px");
getElementById ("id")

Retourne l’élément dont l'ID est donné par l'attribut elementId. Si un tel élément n'existe pas, cela retourne null.

Il s'agit ici d'une méthode très importante pour réaliser facilement des animations, car elle vous permet d’identifier facilement n’importe quel élément enfant qui a un identificateur (attribut "id").

eye_right = svgdoc.getElementById("eyeRightId");
L’interface Event

permet de fournir des informations sur un événement, par ex. l’attribut target

function infos(evt) {
var element =  evt.target ; .... }

<circle onclick="infos(evt)" .... />

Exemple DOM alert

Montre quelques méthodes DOM simples

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="7cm" height="6cm" viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg">
  <desc>Exemple qui affiche des alert suite à un evenement onclick
  </desc>

  <script type="text/ecmascript"> <![CDATA[
    function infos(evt) {
      var element = evt.target;
      el_name = element.nodeName;
      el_attributes = element.attributes;
      circle_size = element.getAttribute("r")
      display_text = "Element name = " + el_name;
      display_text += " \nAttributes = " + el_attributes;
      display_text += " \nCircle size = " + circle_size;
      alert(display_text);
      element.setAttribute("fill", "yellow");
    }
  ]]> </script>

  <!-- S'execute a chaque clic -->
  <circle onclick="infos(evt)" cx="300" cy="225" r="100" fill="red"/>

  <text x="300" y="480" 
        font-family="Verdana" font-size="32" text-anchor="middle">
    Cliquer sur le cercle et lire le popup ...
  </text>
</svg>

Gestionnaire d'événements SVG

Voici quelques-uns des plus importants gestionnaires d'événements SVG: (Pour une liste complète, voir: W3C-SPEC)

  • onmouseover: exécuté lorsque le curseur se déplace au-dessus d'un objet
  • onmouseout: exécuté lorsque le curseur quitte un objet
  • onmousemove: exécuté lorsque le curseur se déplace sur un objet
  • onclick: exécuté quand l'utilisateur clique sur un objet
  • onload: déclenché lorsqu'un fichier SVG a été chargé
  • onzoom: déclenché après que l'utilisateur change le niveau du zoom, soit par une interaction directe de l'utilisateur ou de tout changement à la propriété currentScale disponible sur l'interface SVGSVGElement.
  • onscroll: déclenché lorsque l'utilisateur fait défiler un svg graphiques
  • onresize: déclenché lorsqu'un document a été redimensionnée

Exemple DOM simple

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" 
          "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Created with Inkscape (http://www.inkscape.org/)
 Daniel Schneider @ tecfa.unige.ch (DKS)
 March 2005
 Modified some Inkscape output: missing doctype, opacity
 Added script and events
 -->
<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  height="600.00000" width="800.00000"
  y="0.00000000" x="0.00000000"
  version="1.0">

  <title>Simple Interactivity with Dom</title>
  <desc>This is a simple SVG-DOM demo. Clicking on buttons will change the face, i.e. modifiy XML/SMIL attributes. The drawing was made (quickly) with Inkscape. I did not try to change CSS styles, so I made a few manual changes to the original static SVG which is in file omme.svg</desc>
  <defs>
   <script type="text/ecmascript">

   <![CDATA[

  // variables globales qu'on utilise dans les 2 fonctions
  var svgdoc, eye_right, eye_left, mouth_angry, mouth_happy, mouth_sad ;

  // set to 0 in production, 1 for things to debug, 2 for things fixed
  // var debug = 2;
  var debug = 1;

  function init (big_bang) {
    svgdoc =    big_bang.target.ownerDocument;          // instance of the document
    eye_right = svgdoc.getElementById("eyeRightId");    // getElementById()
    eye_left =  svgdoc.getElementById("eyeLeftId");   
    if (debug==2) alert("eyeLeftId = " + eye_left);
    mouth_angry = svgdoc.getElementById("angry");   
    mouth_happy = svgdoc.getElementById("path1363");   
    mouth_sad   = svgdoc.getElementById("path2168");   
    if (debug==2) alert ("The document did load nicely, global variables are defined");
   }

    function face_change(eye_color, emotion) {
     eye_left.setAttribute("fill", eye_color);
     eye_right.setAttribute("fill", eye_color);
     if (debug==2) alert ("mouth emotion =" + emotion);
     switch (emotion) {
     case mouth_angry:
	 mouth_angry.setAttribute ("visibility","visible");
	 mouth_happy.setAttribute ("visibility","hidden");
	 mouth_sad.setAttribute ("visibility","hidden");
	 break;
     case mouth_happy:
	 mouth_angry.setAttribute ("visibility","hidden");
	 mouth_happy.setAttribute ("visibility","visible");
	 mouth_sad.setAttribute ("visibility","hidden");
	 break;
     case mouth_sad:
	 mouth_angry.setAttribute ("visibility","hidden");
	 mouth_happy.setAttribute ("visibility","hidden");
	 mouth_sad.setAttribute ("visibility","visible");
	 break;
     }
    }

    function button_click(evt) {
      var button = evt.target;
      var currentButton = button.getAttribute("id");
      if (debug==2) alert ("button =" + currentButton);
      if (debug==2) alert ("eye_left,style = " + eye_left.getAttribute('style') + " fill = " + eye_left.getAttribute('fill') );
      if (currentButton == "blue_button")  {
        face_change ("blue", mouth_happy );
        }
      else if (currentButton == "rect1333") {
        face_change ("red", mouth_angry);
        }
      else {
        face_change ("black", mouth_sad);
        }
    }

  ]]> </script></defs>
  

  <desc>This inner svg is some hack: onload will not work with the top-level svg. We do need init to work in order to get at the document root (this is not like normal XML it seems).</desc>

  <svg onload="init(evt)">

    <desc>Below is the definition of the head, eyes and mouth </desc>

  <rect
    id="rect1303"
    style="fill:#edca5e;fill-opacity:1.0000000;fill-rule:nonzero;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
    y="314.00000"
    x="177.37018"
    height="188.00000"
    width="122.00000" />

  <path
    id="path1301"
    style="fill:#edca5e;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-284.0000,-122.0000)"
    d="M 676.00000,319.00000 C 676.00000,400.18586 606.60414,466.00000 521.00000,466.00000 C 435.39586,466.00000 366.00000,400.18586 366.00000,319.00000 C 366.00000,237.81414 435.39586,172.00000 521.00000,172.00000 C 606.60414,172.00000 676.00000,237.81414 676.00000,319.00000 L 676.00000,319.00000 z " />

  <desc>Below we have the 2 eyes. Both are deep green for starters.</desc>

  <path
    id="eyeLeftId"
    fill = "#00ff00"
    style="fill-opacity:1;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-284.0000,-122.0000)"
    d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />

  <path
    id="eyeRightId"
    fill = "#00ff00"
    style="fill-opacity:0.75000000;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-153.0000,-125.0000)"
    d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />

    <desc>Below we have 3 mouthes</desc>

  <path
    id="path1363"
    visibility="visibile"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 154.14365,255.24862 C 154.14365,255.24862 169.06078,300.00000 240.33150,298.34255 C 311.60221,296.68509 326.51934,246.96133 326.51934,246.96133" />
  <path
    id="path2168"
    visibility="hidden"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 150.82873,294.22136 C 150.82873,294.22136 165.74586,249.46998 237.01658,251.12743 C 308.28729,252.78489 323.20442,302.50865 323.20442,302.50865" />
  <path
    id="angry"
    visibility="hidden"
    style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    d="M 139.22652,280.11050 L 339.77901,278.45304" />

    <desc>Below are the 3 buttons to the right </desc>

  <rect
    onclick="button_click(evt)"
    id="rect1333"
    style="fill:#ff0000;fill-opacity:1.0000000;stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="197.23756"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
  <rect
    onclick="button_click(evt)"
    id="rect1335"
    style="stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="416.02209"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
  <rect
    onclick="button_click(evt)"
    id="blue_button"
    style="fill:#0000ff;fill-opacity:1.0000000;stroke-width:14.173228;stroke-miterlimit:4.0000000"
    y="306.62982"
    x="474.03317"
    height="79.558014"
    width="77.900551" />
</svg>
</svg>

Note sur la fabrication du dessin:

Le dessin a été fait avec le logiciel InkScape (qui est un très bon logiciel gratuit qui produit du SVG statique), mais il ne fait pas (encore) du dynamique

Il fallait faire 2-3 retouches:

  • remplacer des éléments CSS par des attributs XML (je ne sais pas comment accéder facilement à un élément CSS dans une longe chaîne via le DOM)
  • changer quelques valeurs (opacité, couleurs)
  • corriger qq. bugs mineurs
  • changer qq. id pour des raisons pédagogiques
  • Il faut identifier les id de certains éléments
  • Trop souvent ce type de logiciel produit des path (au lieu d’une cercle par ex.), donc on ne s’y retrouve pas dans le code.
  • Toutefois, on cliquant sur l’objet dans l’éditeur on peut le voir dans l’arbre DOM dans l’éditeur XML.
    Il suffit de noter l’id sur une feuille de papier ou encore de le changer en une valeur intelligible.

Cet exemple:

  • implémente des boutons (à droite) qui changent l’émotion du visage.
  • les yeux changent de couleur (on aurait pu faire cela sans DOM)
  • différentes "bouches" sont cachées/montrées et pour cela il faut un script à mon avis.

Voici quelques éléments du dessin SVG:

  • Voici l’oeil gauche produit par Inkscape, vert au départ.
<path
    id="eyeLeftId" fill = "#00ff00"
    style="fill-opacity:1;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
    transform="translate(-284.0000,-122.0000)"
    d="M 492.00000,311.00000 C 492.00000,330.32997 475.43454,346.00000 455.00000,346.00000 C 434.56546,346.00000 418.00000,330.32997 418.00000,311.00000 C 418.00000,291.67003 434.56546,276.00000 455.00000,276.00000 C 475.43454,276.00000 492.00000,291.67003 492.00000,311.00000 L 492.00000,311.00000 z " />
  • Voici la bouche "angry", une simple ligne (cachée au départ)
<path
 id="angry" visibility="hidden"
 style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:14.173228;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
 d="M 139.22652,280.11050 L 339.77901,278.45304" />
  • Voici le bouton (rouge) qui déclenche le visage "angry"
<rect
    onclick="button_click(evt)"
    id="rect1333"
    style="fill:#ff0000;fill-opacity:1;stroke-width:14.173228"
    y="197.23756"
    x="474.03317"
    height="79.558014"
    width="77.900551" />

Les event handlers

Lorsque l’utilisateur clique sur un des rectangles à droite, un script se déclenche

  onclick="button_click(evt)"

Les variables globales du script

 // variables globales qu'on utilise dans les 2 fonctions
  var svgdoc, eye_right, eye_left, mouth_angry, mouth_happy, mouth_sad ;

La fonction d’initialisation sert à trouver les objets qu’on veut animer:

function init (big_bang) {
    svgdoc =    big_bang.target.ownerDocument;          // instance of the document
    eye_right = svgdoc.getElementById("eyeRightId");    // getElementById()
    eye_left =  svgdoc.getElementById("eyeLeftId");
    mouth_angry = svgdoc.getElementById("angry");
    mouth_happy = svgdoc.getElementById("path1363");
    mouth_sad   = svgdoc.getElementById("path2168");
    }

La fonction button_click qui gère les clics de l’utilisateur sur les rectangles:

function button_click(evt) {
  var button = evt.target;
  var currentButton = button.getAttribute("id");
   if (currentButton == "blue_button")  {
      face_change ("blue", mouth_happy );
      }
  else if (currentButton == "rect1333") {
     face_change ("red", mouth_angry);
     }
  else {
     face_change ("black", mouth_sad);
     }   }

La fonction button_click reçoit un objet informatique (le paramètre "evt") qui contient toutes les informations sur le click (et surtout l’objet sur lequel on a cliqué) et qu’on va sauver dans une variable "button" ici.

var button = evt.target;

la propriété "target" de l’objet "evt" référence l’objet sur lequel on a cliqué

var currentButton = button.getAttribute("id");

Ensuite on identifie le nom du bouton sur lequel on a cliqué (on lui demande son "id"). En fonction de l’id du bouton (donc 1 des 3 rectangles) on appelle une fonction face_change qui va transformer le visage.

face_change ("black", mouth_sad);

Le premier argument donné est une couleur de cheveux (blue, red ou black). Le 2ème est une variable associée à l’objet qu’il faut utiliser pour dessiner la bouche

La fonction face_change:

function face_change(eye_color, emotion) {
  eye_left.setAttribute("fill", eye_color);
  eye_right.setAttribute("fill", eye_color);
  if (debug==2) alert ("mouth emotion =" + emotion);
  switch (emotion) {
    case mouth_angry:
     mouth_angry.setAttribute ("visibility","visible");
	    mouth_happy.setAttribute ("visibility","hidden");
	    mouth_sad.setAttribute ("visibility","hidden");
	    break;
    case mouth_happy:
	     mouth_angry.setAttribute ("visibility","hidden");
	     mouth_happy.setAttribute ("visibility","visible");
	     mouth_sad.setAttribute ("visibility","hidden");
	     break;
    case mouth_sad:
	     mouth_angry.setAttribute ("visibility","hidden");
	     mouth_happy.setAttribute ("visibility","hidden");
	     mouth_sad.setAttribute ("visibility","visible");
	     break;
     }

L’instruction switch nous permet en fonction de l’objet "emotion/bouche" transmise de rendre cet objet visible et les autres invisibles.

Ceci dit, au lieu de rendre visible/invisible un objet on aurait aussi pu l’enlever/ajouter de la scène. Avec une balise "<g>" on peut regrouper des enfants (dessin de la "bouche"). Ensuite, avec le DOM, on peut en ajouter ou enlever

Animation avec le DOM

Exemple 5-1: Exemple dom01 de la spécification française

A notre avis, il faut surtout utiliser cette fonctionnalité (au lieu des balises animation de SVG):

  • lorsque certaines types d’animation et d’interpolation n’existent pas, par exemple un rectangle qui se promène sur l’écran au hasard (on ne connaît pas son chemin)
  • lorsqu’on utilise un navigateur de type Firefox qui n’implémente pas encore les animations.

Bibliothèques JavaScript

Une autre possibilité est de créer, animer et/ou manipuler les éléments SVG à l'aide d'une bibliothèque JavaScript. Ces bibliothèques mettent à disposition une interface de programmation (API) qui permet d'interagir avec les éléments SVG. Voici deux exemples de bibliothèques :

  • Raphaël : bibliothèque qui est compatible avec les navigateurs plus anciens
  • Snap SVG : bibliothèque plus moderne, mais compatible avec des versions plus récentes des navigateurs