Approfondissements : système de coordonnées, transformations.



Source : livre svg Essentials de O'REILLY.



"The world of SVG is an infinite canvas."

La surface du canevas que le document SVG utilise est appelée le Viewport du document SVG.
Elle est définie de la manière suivante :
dans la balise <svg>, avec les attributs width et height pour les dimensions (et les attributs x et y pour la position dans le navigateur).


Exemple :
Je veux dessiner un rectangle
<svg width="200" height="150">
<rect x="10" y="10" width="50" height="30"
style="stroke: black; fill: none;" />
</svg>

Système de coordonnée par défaut
Je définis une surface initiale où va être contenu le dessin que je crée. Quelle longueur, quelle largeur.
Puis je dois lui donner un système de coordonnées.
Il existe un système de coordonnées pas défaut.
L'origine (0,0) est en haut à gauche du viewport et l'unité de longueur est un pixel. (1,1) est à 1pixels sur l'axe des x et 1 pixel sur l'axe des y de l'origine (0,0).

Les unités de longueur :
Le pixel est l'unité de longueur par défaut.

o                       Les longeurs sont indiqués soit par un nombre, soit par les unités absolues ou relatives habituelles:

o                                     em, ex (largeur d'un "m" et hauteur d'un "x" de la fonte courante)

o                                     px (pixels, unités définies par le device)

o                                     pt, pc (points, et ??). Normalement le client indique à combien de pixels correspond pt ou pc, pareils pour   les cm, mm et in.

o                                     cm, mm, in

o                                     pourcentages (par rapport au viewport)

o                       La signifcation de nombres sans unités s'établit par rapport au unités utilisés pour définir le viewport (pixels par défaut)

o                       Note: On le choix d'ignorer les subtilités du système des longueurs, mais suivant la tâche il faut les maîtriser et relire la spécification.

 

 

Dans l'exemple ci-dessus: le canevas est un rectangle de largeur 200 pixels et hauteur 150 pixels. Il apparaîtra à l'écran en dépendant du système de l'utilisateur.(de la résolution de son écran par exemple).
Le rectangle se place en (10, 10) dans le sytème de coordonnées par défaut. Et sa largeur est de 50 pixels et sa hauteur de 30 pixels.

On peut avoir différents cas de figures:
<svg width="70mm" height="70mm">
<rect x="10" y="10" width="50" height="30"

style="stroke: black; fill: none;" />
</svg>
Le rectangle est toujours en (10 pixels, 10 pixels) dans le sytème de coordonnées par défaut. Et sa largeur est de 50 pixels et sa hauteur de 30 pixels.

<svg width="200" height="200">
<rect x="10mm" y="10mm" width="15mm" height="10mm"

style="stroke: black; fill: none;" />
</svg>
Le rectangle est à (10 mm, 10 mm) dans le sytème de coordonnées par défaut. Et sa largeur est de 15mm et sa hauteur de 10mm.

Modification du système de coordonnées par défaut.
On peut modifier le système de coordonnées par défaut avec l'attribut viewBox de l'élément svg.
Je peux modifier les coordonnées de l'origine. (je peux translater le système de coordonnées).
Je peux modifier le valeur de l'unité de l'axe des x et la valeur de l'unité de l'axe des y. (je peux "scaler" le système de coordonnées).

<svg width="200" height="150" viewBox="0 0 400 300">
<rect x="10" y="10" width="50" height="30"
style="stroke: black; fill: none;" />
</svg>

Le rectangle diminue de moitié… dans le sytème de coordonnée local, une unité locale vaut 0.5 pixels.(200/400).

Cas particuliers:
Si je transforme le système de coordonnées et que l'axe des x et l'axe des y n'ont pas le même "rapport": une unité locale ne représente pas la même longueur sur les deux axes.

Exemple :
<svg width="200" height="150" viewBox="0 0 100 150">
<rect x="10" y="10" width="50" height="50"
style="stroke: black; fill: none;" />
</svg>

Dans le système de coordonnées initial, j'ai un carré et dans le système de coordonnées local je n'ai plus forcément un carré : j'ai un rectangle de largeur 100 pixels et de hauteur 50 pixels.
Alors par défaut SVG, va maintenir "la proportion" et dessiner un carré.
Si on ne veut pas que svg maintienne la proportion il faut utiliser l'attribut suivant:
PreserveAspectRatio et lui affecter la valeur none. Les objets seront déformés mais resteront dans la ViewBox.

On peut affecter d'autres valeurs à l'attribut PreserveAspectRatio :
PreserveAspectRatio="alignement [meet / slice]"
Voir p20-23 svg Essentials de O'REILLY

http://www.yoyodesign.org/doc/w3c/svg1/coords.html - PreserveAspectRatioAttribute

http://tecfa.unige.ch/guides/tie/html/svg-intro/svg-intro-6.html - 96346

 

Systèmes de coordonnées imbriqués
"Nested Systems of Coordinates"

On peut écrire du code de la façon suivante:
<svg width="200px" height="200px" viewBox="0 0 200 200">
<circle cx="25" cy="25" r="25" style="stroke: black; fill: none;"/>
<rect x="100" y="5" width="30" height="80" style="stroke: blue; fill: none;"/>

<svg x="100px" y="5px" width="30px" height="80px" viewBox="0 0 50 50"
preserveAspectRatio="xMaxYMax meet">
<circle cx="25" cy="25" r="25" style="stroke: black; fill: none;"/>
</svg>

</svg>

On peut imbriquer des fichiers SVG et donc insérer des canevas avec leurs sytèmes de coordonnées propres.
Ici on a voulu reproduire le cercle à l'intérieur du rectangle :
au lieu de redimmensionner le cercle et de le déplacer dans le rectangle, on crée un nouveau canevas qui se superpose au rectangle et on dessine le cercle dans ce nouveau canevas.



Illustration SVG du fonctionnement du système de coordonnées...

 

Formules: xm=evt.getClientX()* et ym=evt.getClientY()* renvoient les coordonnées du pointeur dans la fenêtre, l'origine (0;0) étant l'angle supérieur gauche de la zone SVG.
Ces données ne dépendent pas des valeurs données dans viewBox, elles ne peuvent être utilisées telles quelles pour placer un objet ou autre action.
Supposons que les paramètres sont les suivants:
W pour width et H pour height (dans le fichier HTML ou dans le fichier SVG s'il est appelé seul)
viewBox="x0 y0 lo la" (dans le fichier SVG)
Les coordonnées SVG seront alors x0+xm*lo/W et y0+ym*la/H .....

* voir scripting

 

Les transformations

L'attribut Transform...

voir sur les différents sites l'écriture...

http://www.euroclid.fr/Cours_SVG/slide22.htm

http://tecfa.unige.ch/guides/tie/html/svg-intro/svg-intro-6.html - 96346

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

 

Il faut bien comprendre que la transformation s'applique au sytème de coordonnée attaché à l'objet.

Exemple
<svg width="400px" height="400px" viewBox="0 0 400 400">
<rect id="square" x="10" y="10" width="20" height="20"style="fill: none; stroke: black;"/>
<use xlink:href="#square" transform="scale(2)"/>
</svg>

Dans cet exemple simple, on voit que le carré a doublé (en longueur et épaisseur des traits!) ET qu'il a été "déplacé"…c'est ce point qu'il faut bien comprendre.
Le système de coordonnée a été modifié : une unité vaut 2 pixels.
Et le rectangle qui est en (10,10) l'est toujours dans le nouveau système de coordonnées mais se retrouve en (20,20) dans l'ancien système de coordonnées.

D'autre part, si je ne veux pas que l'épaisseur de mon trait double également il faut prévoir de diviser l'épaisseur du trait du facteur inverse de la transformation. Dans cet exemple, il faut affecter la valeur 0.5 à l'attibut stroke pour que l'épaisseur soit toujours de 1 pixel.

<svg width="400px" height="400px" viewBox="0 0 400 400">
<rect x="10" y="10" width="20" height="20"style="fill: none; stroke: black;"/>
<rect x="10" y="10" width="20" height="20"style="fill: none; stroke: black; stroke-width: 0.5;" transform="scale(2)"/>
</svg>

Si je veux que le rectangle ne se déplace pas: il faut utiliser la translation pour "le faire revenir à sa place" :
<rect x="10" y="10" width="20" height="20"style="fill: none; stroke: black; stroke-width: 0.5;" transform="translate(-10 , -10) scale(2)"/>

Même principe avec la rotation :
Si je veux appliquer une rotation à un objet en son centre (s'il en a un!), il faut appliquer la formule suivante : rotate (angle, centerX, center Y).
Qui équivaut à la formule suivante :
translate(centerX, centerY) rotate (angle) translate(-centerX, -centerY)

Attention!
C'est la même chose d'écrire:
<rect x="10" y="10" width="20" height="20"style="fill: none; stroke: black; stroke-width: 0.5;" transform="scale(2)"/>
et :
<g transform="scale(2)">
<rect x="10" y="10" width="20" height="20"style="fill: none; stroke: black; stroke-width: 0.5;"/>
</g>

 

Exercices

Dessiner en svg le dessin décrit ci-dessous, dans un Viewport de 500*500 pixels.

 

Correction:
L'exercice consiste à revenir à un système de coordonnées comme celui qui est présenté sur le dessin.
Il faut utiliser la viewBox : viewBox(0 0 10 10).
Ainsi une unité vaut maintenant 500/10=50 pixels.
Et on peut raisonner dans un nouveau sytème de coordonnées dont l'origine est toujours en haut à gauche.
Pour déplacer le sytème de coordonnée il faut faire une translation jusqu'au point de coordonnées (5,5) dans le nouveau sytème.
Il n'existe pas qu'une solution!

Attention au stroke-with!!
Si on veut qu'il soit d'une épaisseur "normale" (de 1 pixel par exemple), il faut donner comme valeur 1/5 = 0.2. car 0.2unité*50=1!!

<?xml version="1.0" 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="500" height="500"
viewBox="0 0 10 10">
<rect fill="rgb(255,255,192)" stroke="rgb(0,0,0)" stroke-width="0" x="0"
y="0" width="10" height="10"/>
<line fill="none" stroke="rgb(0,0,0)" stroke-width="0.02" x1="5" y1="0" x2="5"
y2="10"/>
<line fill="none" stroke="rgb(0,0,0)" stroke-width="0.02" x1="0" y1="5" x2="10"
y2="5"/>
<g transform="translate(5 5)">
<rect fill="rgb(255,0,0)" stroke="rgb(0,0,0)"
stroke-width="0.02" x="-4"
y="-4" width="7" height="1"/>
<circle fill="rgb(0,0,0)" stroke-width="0.02" cx="2" cy="3" r="1"/>
</g>
</svg>