UP PREVIOUS NEXT   Technologies Internet et Education, © TECFA
  4. Interactivité avec le DOM et EcmaScript

4. Interactivité avec le DOM et EcmaScript

4.1 Introduction et exemple de sensibilisation

  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 4-1: Simple switch avec DOM

<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>
 
<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>
 

Explications:

<circle onclick="circle_click(evt)
" cx="300" cy="225" r="100" fill="red"/>
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)
;

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

4.2 Introduction au scripting avec DOM

A. Placement et initialisation du script

<script type="text/ecmascript"> 
  <![CDATA[
  function circle_click(evt
) {
    .....
    }
  ]]>
 
</script>
<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>

B. Le déboggage

// set to 0 in production, 1 for things to debug, 2 for things fixed
var debug = 1;
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 ....

C. Classes et méthodes SVG DOM et XML DOM 2

L'interface SVGDocument

svgdoc = big_bang.target.ownerDocument;// instance of the document

eye_right = svgdoc.getElementById ("eyeRightId"); // getElementById()

L'interface SVGSVGElement

D. Eléments utiles du XML DOM2

L'interface Document

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")

element = ... // objet qui représente un élément

element. getAttribute("r")

setAttribute ("name", "value")

element. setAttribute ("fill", "yellow");

getElementById ("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 4-2: DOM alert

  <script type="text/ecmascript"> <![CDATA[
    function infos(evt) {
      var element = evt.target
; XML DOM
      el_name = element.nodeName
; // XML DOM2
      el_attributes = element.attributes; 
// XML DOM2
      circle_size = element.getAttribute("r") 
// XML DOM2
      display_text = "Element name = " + el_name;
      display_text += " \nAttributes = " + el_attributes;
      display_text += " \nCircle size = " + circle_size;
      alert(display_text);
      element.setAttribute
("fill", "yellow"); //XML DOM2
    }
  ]]> </script>
 
  <!-- S'exécute a chaque clic -->
  <circle onclick="infos(evt)"
 cx="300" cy="225" r="100" fill="red"/>

4.3 Exemple DOM simple

Exemple 4-3: Simple interaction avec DOM

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 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

  • Fonction qui gère les clics des 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
  • 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

UP PREVIOUS NEXT -- TIE