Le scripting


Sources :

http://www.w3.org/TR/SVG/script.html

http://www.w3.org/2002/Talks/0328-Amsterdam-IH/SVGDOM2slide.svgz

http://pilat.free.fr/routines/js_dom.htm

Livre SVG essential.O'Reilly


Création de graphique svg intéractif :
On peut écrire des scripts pour rendre intéractif les graphiques SVG.
Le langage le plus utilisé est Javascript (ou ECMA Script qui veut dire "the European Computer Manufacturer's Association standard version of Javascript).
L'interaction a lieu quand les objets du graphique répondent à des évènements.

Les évènements
Les objets peuvent répondre :

Pour permettre à un objet de répondre à un évènement on lui ajoute un attribut de la forme suivante : oneventName.
La valeur de cet attribut sera générallement l'appel d'une fonction javascript.

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="300" height="200" viewBox="0 0 300 200">
<script type="text/ecmascript">
<![CDATA[
function enlarge_circle(evt)
{
var circle = evt.getTarget();
circle.setAttribute("r", 50);
}
function shrink_circle(evt)
{
var circle = evt.getTarget();
circle.setAttribute("r", 25);
}
// ]]>
</script>
<circle cx="150" cy="100" r="25" fill="red"
onmouseover="enlarge_circle(evt)"
onmouseout="shrink_circle(evt)"/>
<text x="150" y="175" style="text-anchor: middle;">
Mouse over the circle to change its size.
</text>
</svg>

Quel genre d'action peut-on créer sur un fichier SVG?
On peut modifier les attributs des objets : leur taille, leur couleur, leur opacité, leur position, leur visibilité...etc.
On peut créer ou "détruire" des objets.
On peut lancer des animations.

Comment ça fonctionne ?

·        Le DOM.
"The Document Object Model (DOM) is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The DOM is an application programming interface (API) for HTML and XML documents."
http://wdvl.internet.com/Seminars/DHTML/DOM/Resources.html
http://tecfa.unige.ch/guides/tie/html/xml-dom/xml-dom-4.html#pgfId-1000014765
http://www.w3.org/TR/SVG/svgdom.html

 

·        Ecmascript
voir documentation : http://www.w3.org/TR/2001/REC-SVG-20010904/ecmascript-binding.html
méthodes, propriétés. spécifique svg.
 Pré-requis : principe de base langage javascript.

 

·        Comment lier un script et SVG ?

La balise <script> dans le fichier SVG
<script><![CDATA[
................. votre script ......................
]]></script>

Ou :

L'appel à un fichier javascript externe
<script xlink:href="nom_fichier" />


Galerie d'exemples :


Cliquez sur un objet et bouton gauche appuyé, déplacez la souris

Intérêt : utilisation de getClientX(), et getClientY()


Source du fichier SVG :

<svg width="500" height="400">
<script>
<![CDATA[
var appui=false,cible="",xd2=0,yd2=0,xd1=0,yd1=0,objet="";


 
function bouger(evt)
{xm=evt.getClientX();ym=evt.getClientY();
if ((xm<=5)||(xm>=495)||(ym<=5)||(ym>=395)) {appui=false}
else
{if (((cible=="rectangle")||(cible=="cercle"))&&(appui==true))
{svgdoc=evt.getTarget().getOwnerDocument();
tran=objet.getAttribute("transform");
j=1;for (i=1;i<5;i++) {posi=tran.indexOf(" ",j+1);j=posi};
tran=tran.substring(0,posi);
depx=xm+xd1-xd2;depy=ym+yd1-yd2;
if (cible=="rectangle") 
{if (depx<0) {depx=0};if (depx>400) {depx=400};if (depy<0) {depy=0};if (depy>350) {depy=350}};
if (cible=="cercle") 
{if (depx<50) {depx=50};if (depx>450) {depx=450};if (depy<50) {depy=50};if (depy>350) {depy=350}};
poly=tran+" "+depx+" "+depy+")";
objet=svgdoc.getElementById(cible);
objet.setAttribute("transform",poly)}}}
 
function lacher(evt)
{appui=false}
 
function cliquer(evt)
{cible=evt.getTarget().getAttribute("id");svgdoc=evt.getTarget().getOwnerDocument();
if ((cible=="rectangle")||(cible=="cercle"))
{appui=true;
xm=evt.getClientX();ym=evt.getClientY();
objet=svgdoc.getElementById(cible);
tran=objet.getAttribute("transform");j=1;
for (i=1;i<5;i++) {posi=tran.indexOf(" ",j+1);j=posi}
posi2=tran.lastIndexOf(" ");
tranx=tran.substring(posi,posi2);xd1=parseInt(tranx,10); 
longue=tran.toString().length-1;posi2=posi2+1;
trany=tran.substring(posi2,longue);yd1=parseInt(trany,10);
xd2=xm;yd2=ym}}
]]>
</script>
 
<g onmousemove="bouger(evt)" onmousedown="cliquer(evt)" onmouseup="lacher(evt)">
<rect x="0" y="0" width="500" height="400" style="stroke-width:1; stroke:#0E0E0E; fill:#EEEEEE"/>
<rect id="rectangle" x="0" y="0" width="100" height="50" transform="matrix(1 0 0 1 50 50)" style="stroke-width:1; stroke:#0E0E0E; fill:red"/>
<ellipse id="cercle" cx="0" cy="0" rx="50" ry="50" transform="matrix(1 0 0 1 300 200)" style="stroke-width:1; stroke:#0E0E0E; fill:green"/>
</g>
</svg>

Cliquer sur la taille du tshirt qui vous convient : small, medium, large.


Intérêt : code simple et net :). source : SVG essentials. O'reilly.


Source du fichier SVG :

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="400" height="250" viewBox="0 0 400 250"
onload="init(evt)">

<script type="text/ecmascript">
<![CDATA[
var scaleChoice = 1;
var scaleFactor = new Array( 1.25, 1.5, 1.75 );

function init( evt )
{transformShirt();}

function setScale( n )
{
obj = svgDocument.getElementById( "scale" + scaleChoice );
obj.setAttribute( "fill", "white" );
scaleChoice = n;
obj = svgDocument.getElementById( "scale" + scaleChoice );
obj.setAttribute( "fill", "#ffc" );
transformShirt();
}
function transformShirt( )
{
var obj = svgDocument.getElementById( "shirt" );
obj.setAttribute( "transform","scale(" + scaleFactor[scaleChoice] + ")");
obj.setAttribute( "stroke-width",1 / scaleFactor[scaleChoice] );
}
// ]]>
</script>

<defs>
<path id="shirt"
d="M -6 -30, -32 -19, -25.5 -13, -22 -14, -22 30, 23 30,
23 -14, 26.5 -13, 33 -19, 7 -30
A 6.5 6 0 0 1 -6 -30"
fill="white" stroke="black"/>
</defs>
<use xlink:href="#shirt" x="150" y="150"/>
<g onclick="setScale(0)">
<rect id="scale0" x="100" y="10" width="30" height="30"
fill="white" stroke="black"/>
<text x="115" y="30" text-anchor="middle">S</text>
</g>
<g onclick="setScale(1)">
<rect id="scale1" x="140" y="10" width="30" height="30"
fill="#ffc" stroke="black"/>
<text x="155" y="30" text-anchor="middle">M</text>
</g>
<g onclick="setScale(2)">
<rect id="scale2" x="180" y="10" width="30" height="30"
fill="white" stroke="black"/>
<text x="195" y="30" text-anchor="middle">L</text>
</g>
</svg>



Exemples de menus déroulants, etc



Cliquer sur le bouton droit de la souris et exploiter le menu

Intérêt : les balises <menu>...</menu>,<item>...</item>..etc...assez complexe.


Source du fichier SVG :

<svg width="400" height="300" onmousemove="init(evt)">
<defs>
<menu id="menu1" >
<header>Menu utilisateur</header>
<item action="ZoomIn">Zoom</item>
<item id="clone" action="OriginalView">Vue originale</item>
<item/>
<item onactivate="clone_objet(evt)">Cloner</item>
<menu>
<header>Colorier</header>
<item onactivate="colorier(evt,'green')">Vert</item>
<item onactivate="colorier(evt,'red')">Rouge</item>
<item onactivate="colorier(evt,'blue')">Bleu</item>
<item onactivate="colorier(evt,'yellow')">Jaune</item>
</menu>
<item/>
<item action="SaveSnapshotAs">Sauver SVG</item>
<item action="ViewSource">Voir le source</item>
<item onactivate="aide(evt)">Aide</item>
</menu>
<menu id="menu0" >
<item action="ZoomIn">Zoom</item>
<item id="clone" action="OriginalView">Vue originale</item>
<item/>
<menu>
<header>Colorier</header>
<item onactivate="colorier(evt,'green')">Vert</item>
<item onactivate="colorier(evt,'red')">Rouge</item>
<item onactivate="colorier(evt,'blue')">Bleu</item>
<item onactivate="colorier(evt,'yellow')">Jaune</item>
</menu>
<item/>
<item action="SaveSnapshotAs">Sauver SVG</item>
<item action="ViewSource">Voir le source</item>
<item onactivate="aide(evt)">Aide</item>
</menu>
<menu id="menu2" >
<header>Menu utilisateur</header>
<item action="ZoomIn">Zoom</item>
<item id="clone" action="OriginalView">Vue originale</item>
<item/>
<menu>
<header>Colorier</header>
<item onactivate="colorier(evt,'green')">Vert</item>
<item onactivate="colorier(evt,'red')">Rouge</item>
<item onactivate="colorier(evt,'blue')">Bleu</item>
<item onactivate="colorier(evt,'yellow')">Jaune</item>
</menu>
<menu>
<header>Police</header>
<item onactivate="police(evt,'Arial')">Arial</item>
<item onactivate="police(evt,'Times New Roman')">Times New Roman</item>
<item onactivate="police(evt,'Tahoma')">Tahoma</item>
<item onactivate="police(evt,'Verdana')">Verdana</item>
</menu>
<item/>
<item action="SaveSnapshotAs">Sauver SVG</item>
<item action="ViewSource">Voir le source</item>
<item onactivate="aide(evt)">Aide</item>
</menu>
</defs>
<script><![CDATA[
var n=0;
var svgdoc="";
var cible,XPos,YPos;
function init(evt)
{svgdoc=evt.getTarget().getOwnerDocument();
cible=evt.getTarget();XPos=evt.getClientX();YPos=evt.getClientY()}

function faire_menus(nom_menu)
{var newMenuRoot=parseXML(printNode(document.getElementById(nom_menu)),contextMenu);
contextMenu.replaceChild(newMenuRoot,contextMenu.firstChild)}

function aide()
{alert("Testez le menu contextuel\nqui varie suivant l'objet\nsur lequel vous cliquez\navec le bouton droit")}

function clone_objet(evt)
{n=n+1;
objet=svgdoc.getElementById("rectangle");
var newnode = objet.cloneNode(true);
newnode.setAttribute ("x",100+10*n);newnode.setAttribute ("y",100+10*n);
newnode.getStyle().setProperty("fill","blue");
var contents = svgdoc.getElementById ('affiche');
newnode = contents.appendChild (newnode)}

function colorier(evt,couleur)
{cible.getStyle().setProperty("fill",couleur)}

function police(evt,fonte)
{cible.getStyle().setProperty("font-family",fonte)}

]]></script>
<rect x="0" y="0" width="400" height="300" onmousemove="faire_menus('menu0')" style="fill:white;opacity:0.2"/>
<g id="affiche">
<text id="texte" onmousemove="faire_menus('menu2')" x="200" y="40" style="text-anchor:middle;font-size:15;font-family:Arial;fill:red">Testez le menu contextuel (bouton droit)</text>
<rect id="rectangle" onmousemove="faire_menus('menu1')" onclick="clone_objet(evt)" x="50" y="50" width="100" height="50" style="fill:green"/>
</g>
</svg>


Cliquer sur le rectangle et choisissez la couleur de remplissage!


Source du fichier SVG :

<svg width="500" height="400">
<script><![CDATA[
alertes=new Array("LightGrey","black","yellow","red",14,"Arial",150,100,200,150);
chaines=new Array("Coloriez le rectangle","en rouge","en bleu","en noir","Je confirme");
var choix=0,nb_chaines=0;

function alerte(evt)
{svgdoc=evt.getTarget().getOwnerDocument();
node=svgdoc.createElement("rect");node.setAttribute("id","fenetre");
node.setAttribute("x",alertes[6]);node.setAttribute("y",alertes[7]);
node.setAttribute("width",alertes[8]);node.setAttribute("height",alertes[9]);
style="fill:"+alertes[0]+";stroke:"+alertes[1];
node.setAttribute("style",style);
ou=svgdoc.getElementById("affichage");ou.appendChild(node);
nb_chaines=chaines.length-1;
node=svgdoc.createElement("text");node.setAttribute("id","invite0");
node.setAttribute("x",alertes[6]+alertes[8]*0.5);node.setAttribute("y",alertes[7]+alertes[4]*1.5);
style="text-anchor:middle;font-size:"+alertes[4]+";font-family:"+alertes[5]+";fill:"+alertes[3];
node.setAttribute("style",style);
texte=svgdoc.createTextNode(chaines[0]);
node.appendChild(texte);ou=svgdoc.getElementById("affichage");ou.appendChild(node)
for (i=1;i<nb_chaines;i++)
{node=svgdoc.createElement("text");node.setAttribute("id","invite"+i.toString(10));
node.setAttribute("x",alertes[6]+40);node.setAttribute("y",alertes[7]+(i+1)*alertes[4]*1.5);
style="text-anchor:left;font-size:"+alertes[4]+";font-family:"+alertes[5]+";fill:"+alertes[3];
node.setAttribute("style",style);
texte=svgdoc.createTextNode(chaines[i]);
node.appendChild(texte);ou=svgdoc.getElementById("affichage");ou.appendChild(node);
node=svgdoc.createElement("circle");node.setAttribute("id","case"+i.toString(10));
node.setAttribute("cx",alertes[6]+20);node.setAttribute("cy",alertes[7]+(i+1)*alertes[4]*1.5-5);
node.setAttribute("r",5);
node.setAttribute("style","fill:white;stroke:black;stroke-width:3");
node.addEventListener("click",choisir,false);
ou=svgdoc.getElementById("affichage");ou.appendChild(node)
node=svgdoc.createElement("rect");node.setAttribute("id","choix"+i.toString(10));
node.setAttribute("x",alertes[6]+20);node.setAttribute("y",alertes[7]+i*alertes[4]*1.5+10);
node.setAttribute("width",alertes[8]-40);node.setAttribute("height",alertes[4]*1.5);
node.setAttribute("style","fill-opacity:0");
node.addEventListener("click",choisir,false);
ou=svgdoc.getElementById("affichage");ou.appendChild(node)};
node=svgdoc.createElement("rect");node.setAttribute("id","oui1");
node.setAttribute("x",alertes[6]+alertes[8]/4);
node.setAttribute("y",alertes[7]+alertes[9]-10-alertes[4]*1.5);
node.setAttribute("width",alertes[8]/2);node.setAttribute("height",alertes[4]*1.5);
style="fill:"+alertes[2]+";stroke:"+alertes[1];
node.setAttribute("style",style);
ou=svgdoc.getElementById("affichage");ou.appendChild(node);
node=svgdoc.createElement("text");node.setAttribute("id","oui2");
node.setAttribute("x",alertes[6]+alertes[8]/2);
node.setAttribute("y",alertes[7]+alertes[9]-15);
style="text-anchor:middle;font-size:"+alertes[4]+";font-family:"+alertes[5]+";fill:"+alertes[3];
node.setAttribute("style",style);texte=svgdoc.createTextNode(chaines[nb_chaines]);
node.appendChild(texte);ou=svgdoc.getElementById("affichage");ou.appendChild(node);
node=svgdoc.createElement("rect");node.setAttribute("id","oui3");
node.setAttribute("x",alertes[6]+alertes[8]/4);node.setAttribute("y",alertes[7]+alertes[9]-10-alertes[4]*1.5);
node.setAttribute("width",alertes[8]/2);node.setAttribute("height",alertes[4]*1.5);
node.setAttribute("style","fill-opacity:0");
node.addEventListener("click",efface,false);
ou=svgdoc.getElementById("affichage");ou.appendChild(node)}

function choisir(evt)
{svgdoc=evt.getTarget().getOwnerDocument();cible=evt.getTarget().getAttribute("id");
choix=parseInt(cible.substring(5,6));nb_chaines=chaines.length-1;
for (i=1;i<nb_chaines;i++)
{objet=svgdoc.getElementById("case"+i.toString(10));
if (i==choix) {couleur="red"} else {couleur="white"};
objet.getStyle().setProperty("fill",couleur)}}

function efface(evt)
{svgdoc=evt.getTarget().getOwnerDocument();nb_chaines=chaines.length-1;
objet=svgdoc.getElementById("fenetre");
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet);
objet=svgdoc.getElementById("invite0");
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet);
for (i=1;i<=3;i++)
{objet=svgdoc.getElementById("oui"+i.toString(10));
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet)};
for (i=1;i<nb_chaines;i++)
{objet=svgdoc.getElementById("invite"+i.toString(10));
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet);
objet=svgdoc.getElementById("choix"+i.toString(10));
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet);
objet=svgdoc.getElementById("case"+i.toString(10));
contents = svgdoc.getElementById ("affichage");contents.removeChild (objet)};
change_attribut(evt)}

function change_attribut(evt)
{svgdoc=evt.getTarget().getOwnerDocument();
objet=svgdoc.getElementById("rectangle");
switch(choix)
{case 1 :couleur="red";break;
case 2 :couleur="blue";break;
case 3 :couleur="black";break};
objet.getStyle().setProperty("fill",couleur)}
]]></script>

<rect x="0" y="0" width="500" height="400" style="fill:white"/>
<g id="affiche">
<text id="texte" x="150" y="50" style="text-anchor:middle;font-size:25;font-family:Arial;fill:red">Cliquez sur le rectangle</text>
<rect id="rectangle" onclick="alerte(evt)" x="50" y="100" width="100" height="50" style="fill:green"/>
</g>
<g id="affichage">
</g>
</svg>

 


Exemples sympas et avancés :



Vous pouvez sélectionner l'écriture hexadécimale de la couleur obtenue
la copier ( bouton droit sur le SVG ) puis la coller dans votre code.


Vous pouvez écouter de la musique...
Attention! Ne fonctionne pas avec Nescape.



 


Exemple avec une animation :

<svg width="300" height="150" viewBox="0 0 300 150"
        onload="init(evt)"> 
<script type="text/ecmascript">
<![CDATA[
function init( evt )
{
        /* initialization code goes here */
}
function setMessage( visStatus )
{
    var message = svgDocument.getElementById( "message" );
    message.setAttribute( "visibility", visStatus );
}
// ]]>
</script>
<g id="button">
    <rect x="10" y="10" width="40" height="20" rx="4" ry="4"
        style="fill: #ddd;"/>
    <text x="30" y="25" style="text-anchor: middle;">Start</text>
</g>
<text id="message" x="60" y="25" visibility="hidden">
    Animation in progress.
</text>
<g transform="translate(100, 60)">
    <path d="M-25 -15, 0 -15, 25 15, -25 15 Z"
               style="stroke: gray; fill: #699;">
        
        <animateTransform id="trapezoid" attributeName="transform"
            type="rotate" from="0" to="360"
            begin="button.click"
            dur="6s"
            onbegin="setMessage('visible')"
            onend="setMessage('hidden')"/> 
    </path>
</g>
</svg>

 

http://tecfa.unige.ch/staf/staf-g/sierra/staf2x/scripting/exsimpleanimscript.svg

 

Exercice : prenez votre animation du matin et faites apparaître le texte « mon animation ! » quand l’animation a lieu.