Chapitre 10  Script et DOM

Extrait

Eléments sensibles

Les événements liés à la souris ont évidemment une très grande importance. 


Figure 10-8. Rectangles sensibles

Nous prenons un exemple simple pour pouvoir nous concentrer sur ces événements.

 Ce code définit cinq rectangles

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);">
 
<script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/>
 
<script type="text/ecmascript">
 
<![CDATA[
   
function Init(evt)
   
{
      
RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement);
    }
  ]]>
  </script>
  <g>
     <rect x="10"  y="100" width="90" height="40" fill="blue" opacity="0.4" />
     <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" />
     <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4"
/>
     <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" />
     <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" />
  </g>
  <text x="55"  y="160" text-anchor="middle">highlight</text>
  <text x="155" y="160" text-anchor="middle">magical</text>
  <text x="255" y="160" text-anchor="middle">changing color</text>
  <text x="355" y="160" text-anchor="middle">mutate</text>
  <text x="455" y="160" text-anchor="middle">click</text>
</svg>

Tous ces rectangles placés dans un même groupe ont un attribut opacity avec une valeur de 0.4. 
Nous voulant créer un effet de surbrillance en portant cette valeur à 1.0, quand le pointeur est sur l'un de ces rectangles. 
Surbrillance

Nous prenons le rectangle bleu et faisons de ce rectangle un récepteur en lui attribuant les événements
Nous devons définir les fonctions ECMAScript Highlight et Unhighlight.

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" onload="Init(evt);">
  <script type="text/ecmascript" xlink:href="RemoveWhiteSpace.js"/>
  <script type="text/ecmascript">
  <![CDATA[
    function Init(evt)
    {
       RemoveWhiteSpaceChildNodesOf(evt.target.ownerDocument.documentElement);
    }
    function Highlight(evt)
    {
       evt.target.
setAttribute("opacity", "1.0");
    }
    function Unhighlight(evt)
    {
      
evt.target.
setAttribute("opacity", "0.4");
    }
  ]]>
  </script>
  <g>
    <rect x="10"  y="100" width="90" height="40" fill="blue" opacity="0.4"
         
onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);"/>
<!-- other elements here -->
</svg>

Nous utilisons la propriété target de l'objet MouseEvent pour accéder directement à l'élément <rect> récepteur de cet événement. Quand le pointeur entre dans le rectangle nous donnons la valeur 1.0 à son attribut opacity, et la valeur 0.4 quand le pointeur quitte le rectangle.


Figure 10-9. Surbrillance du rectangle

( essayer comme svg )

Si nous voulons donner la même propriété aux autres rectangles, nous devons leur ajouter les propriétés onmouseover et onmouseout également. Nous avons une solution plus simple. En utilisant la propagation de l'événement – event bubbling, nous pouvons simplement affecter les propriétés onmouseover et onmouseout à l'élément <g>.

  <g onmouseover="Highlight(evt);" onmouseout="Unhighlight(evt);">
    
<rect x="10"  y="100" width="90" height="40" fill="blue" opacity="0.4" />
    
<rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4" />
     <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4"/>
     <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4" />
    
<rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4" />
 
</g>

Ceci fonctionne très bien. 
Si nous voulions accéder à l'élément <g> dans les fonctions, nous utiliserions evt.currentTarget à la place de evt.target.

Changer la couleur

Nous voudrions que le troisième rectangle devienne noir quand nous cliquons sur lui et reprenne ensuite sa couleur.
Nous affectons à l'élément <rect> les événements onmousedown et onmouseup.

    <rect x="210" y="100" width="90" height="40" fill="yellowgreen" opacity="0.4"
          
onmousedown="ChangeColor(evt);" onmouseup="ChangeColor(evt);"/>

Nous devons également définir la fonction associée.

Nous utiliserons la même fonction pour les deux événements en nous servant du type de l'événement. 

Voici le code complet.

    function ChangeColor(evt)
   
{
      
if (evt.type == "mousedown")
          
evt.target.setAttribute("fill", "black");
      
else if (evt.type == "mouseup")
         
evt.target.setAttribute("fill", "yellowgreen");
   
}



Figure 10-10. Rectangle noir quand nous le cliquons

( essayer comme svg )

Quand le pointeur est sur ce rectangle, il passe en surbrillance, quand nous pressons le bouton il devient noir 
et retrouve sa couleur quand nous relâchons le bouton. Il perd sa surbrillance quand le pointeur le quitte.
Cependant, si nous gardons le bouton pressé sur le rectangle, il est noir et en surbrillance, 
mais si nous relâchons le bouton en dehors du rectangle, il perd sa surbrillance mais reste noir. 
L'événement onmouseup n'a pas été perçu par le rectangle, le pointeur n'étant plus sur lui.

Rendre invisible

Nous voulons faire disparaître le rectangle 'mutate' quand la souris est sur le second rectangle, rectangle magique. 
Nous en profitons pour supprimer la surbrillance pour lui. 
Nous lui attribuons les événements

 <rect x="110" y="100" width="90" height="40" fill="green" opacity="0.4"
     
onmouseover="Magical(evt);" onmouseout="Magical(evt);"/>

La fonction Magical très semblable à ChangeColor.

function Magical(evt)
{
   if (evt.type == "mouseover")
      evt.target.nextSibling.nextSibling.setAttribute("visibility", "hidden");
   else
      evt.target.nextSibling.nextSibling.removeAttribute("visibility");
   evt.stopPropagation ();
}


Figure 10-11. Hide rectangle

( essayer comme svg )

Nous utilisons l'élément evt.target pour naviguer dans le DOM tree et changer les attributs d'un autre élément. 
Nous stoppons la propagation de l'événement avec evt.stopPropagation() pour supprimer l'effet de surbrillance.
Transformer un rectangle

Nous voulons qu'en cliquant sur le quatrième rectangle, il devienne une ellipse. 
Comme nous l'avons vu, nous ne pouvons pas changer le type d'un élément, nous devons le remplacer par un autre élément. 
Nous avons également vu qu'une solution économique est d'utiliser les propriétés de visibilité. 
Nous ajoutons un élément <ellipse> à notre document et le cachons avec l'attribut display="none".
Nous affectons l'événement au rectangle et également à l'ellipse

 <rect x="310" y="100" width="90" height="40" fill="orange" opacity="0.4"
        
onclick="Mutate(evt);" />
<ellipse cx="355" cy="120" rx="45" ry="20" fill="orange" display="none"
         onclick="Mutate(evt);" />

Nous avons simplement à faire glisser l'attribut display="none" de l'élément <rect> à l'élément  <ellipse> pour chaque click.

function Mutate(evt)
{
   var elem = evt.target;
   elem.setAttribute("display", "none"); // hide the displayed element ..
   if (elem.nodeName == "rect") // rectangle was displayed ..
      elem.nextSibling.removeAttribute("display"); // .. show ellipse
   else                       // ellipse was be displayed ..
      elem.previousSibling.removeAttribute("display");  // show rectangle
}
 }


Figure 10-12.
Changer la forme

( essayer comme svg )

Comme l'élément <ellipse> est aussi dans le groupe, la surbrillance fonctionne automatiquement aussi pour cet élément. 
Vous devez vous demander quelle est la différence entre les attributs display et visibility attribute. 
Une différence significative est dans la sensibilité aux événements:
Les éléments avec visibility="hidden" sont invisibles et peuvent recevoir un événement en leur ajoutant l'attribut pointer-events="all".
Les éléments avec display="none" sont invisibles et ne peuvent recevoir les événements.
C'est cette dernière propriété que nous voulions.

Double Clicks

Nous voulons faire la différence entre un simple click et un double click du bouton du pointeur. 
Si vous avez lu attentivement les propriétés de MouseEvent, vous avez remarqué la propriété detail. 
Elle est très utile et sa valeur dépend du type de l'événement. 
Avec l'événement onclick elle stocke le nombre de clicks que l'utilisateur fait. 
Nous utilisons le dernier rectangle pour tester ceci.

   <rect x="410" y="100" width="90" height="40" fill="red" opacity="0.4"
        
onclick="ClickCounter(evt);"/>

 Nous créons la fonction ClickCounter et affichons le nombre de clicks sous le rectangle.

function ClickCounter(evt)
{
  
var clickText = evt.target.parentNode.parentNode.lastChild.firstChild;
  
clickText.nodeValue = evt.detail + ". click"
}

 
Figure 10-13. Compteur de clicks

( essayer comme svg )

Le premier click écrit 1. click sous le rectangle. Le second click produira des effets différents:
·Si le temps entre les deux clicks est trop long nous aurons toujours 1. click.
·Si le temps est assez court mais que le pointeur s'est déplacé, nous aurons encore 1. click.
·Si le temps est assez court et que le pointeur n'est pas déplacé nous aurons 2. click.