JeuWeb - Crée ton jeu par navigateur
Article SVG - Scalable Vector Graphics - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Article SVG - Scalable Vector Graphics (/showthread.php?tid=8218)



SVG - Scalable Vector Graphics - Xenos - 14-09-2020

SVG  - Scaled Vector Graphics

Disclaimer

Loin d'être un expert du SVG, je vais tenter d'effleurer la surface de ce standard. Vous ne trouverez pas sur cette page une description exhaustive de tout ce qu'il peut vous apporter mais juste une initiation et quelques trucs qui, j'espère, vous donneront quelques idées et vous feront entrevoir ses possibilités.

Le Standard SVG

Le SVG (Scaled Vector Graphique) est né de la fusion de deux mondes différents. Celui du VML (Microsoft) et du PGML (Adobe). A partir de ces deux source, le W3C commença à travailler sur le standard SVG en 1998.
Sous-famille du XML, il permet de réaliser des dessins vectoriels et des animations via Javascript ou SMIL. Il existe différents standards pour le SVG.
  • SVG 1.0 (September 2001)

  • SVG 1.1 (January 2003) qui vit aussi l'arrivée de SVGT (Tiny) et SVGB (Basic) pour les mobiles.

  • SVG Tiny 1.2 (December 2008)

  • SVG Full 1.2 est actuellement toujours en cours de standardisation.


Désavantages

Autant commencer par les choses désagréables.

Support

Malgré son âge avancé, ce format n'est pas encore pleinement supporté par tous les navigateurs. Internet Explorer requiert un plugin pour le faire fonctionner, FireFox ne supporte pas les fonctions d'animations SMIL, Webkit (Chrome, Safari) contient quelques gros bugs. Seul Opera semble pour le moment tirer son épingle du jeu.

Accessibilité

Le SVG étant en gros un langage pour faire des dessins, ses possibilités sont limitées. Pas de supers effets à la Photoshop, pas de dessins complexes, code source verbeux rendant le source parfois plus gros qu'un PNG, cela demande tout de même de l'investissement et un soupçon d'ingéniosité pour profiter des fonctionnalités offertes par ce standard.

Avantages

Oui, il y en a ! Bah oui. Dans le cas contraire, je ne me fatiguerais pas à faire une page de Wiki dessus.

Interfaçable via Javascript

Etant basé sur le XML, le SVG possède tout un DOM qu'il est possible de modifier / atteindre par le biais de JS.

Intégration SMIL

En version 3.0 chez le W3C depuis Janvier 2008, ce standard permet de réaliser des animations de transition, mouvement avec un timing précis.

CSS Compatible

Les éléments du SVG peuvent répondre aux règles de mise en page définies dans une feuille de style CSS.

Support grandissant

C'est officiel, Microsoft intégrera un support SVG natif dans IE9. Les développeurs de Firefox espèrent intégrer bientôt le support SMIL et WebKit corrige en permanence les bugs.

Comment ça marche

Comme expliqué plus haut, le SVG fait partie de la grande famille XML. Cela signifie qu'il est composé tout simplement de balises et d'attributs.

Structure

En général, les logiciels de dessin vectoriel (inkscape, Illiustrator) permettent de sauvegarder les images en SVG. En ouvrant le fichier ainsi sauvegardé avec un éditeur de texte, on peut facilement observer la structure du fichier

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" version="1.1" overflow="visible"
width="100" height="100" viewBox="0 0 100 100">
<!-- Mettre ici code SVG pour générer l'image -->
</svg>

On retrouve la déclaration XML, le DOCTYPE et la balise SVG qui contiendra la définition de l'image.
Les attributs width, height définissent la taille de l'affichage dans la page HTML.
viewbox spécifie les dimensions de la zone de dessin.
si par exemple vous spécifiez une viewbox de 100 x 100 pixels et une viewbox de 1000 sur 1000, il faudra spécifier les coordonnées d'affichage des éléments dans un espace de 1000 pixels sur 1000 pixels. Le moteur de rendu SVG se chargera de re-dimensionner le contenu pour le faire tenir dans l'espace spécifié par height et width.

La définition du NameSpace xlink est essentielle pour référencer des éléments internes ou externe au fichier (explications plus bas)

Attributs essentiels

Avant de commencer, il est nécessaire de connaîtres quelques attributs qui permettront de donner de la couleur et de la forme aux éléments.
  • fill : couleur de remplissage (ex fill=“red”)

  • stroke : couleur du contour (ex stroke=”#FFCCDD”)

  • stroke-width : largeur du contour (ex: stroke-width=“2”)

  • stroke-dasharray : tableau de valeur pour réaliser des pointillés (ex: stroke-dasharray =“3,1,3”)

  • opacity : détermine l'opacité de l'élément allant de 0 (transparent) à 1 (visible à 100%)


Les couleurs peuvent être exprimées sous forme de nom (white, black), de code HTML (#552299) ou définies à “none” s'il n'y en a pas.

Principaux tags

Autant rentrer dans le vif du sujet et voir les quelques tags simples qui permettent de créer quelques formes vectorielles

Cercle

Trois attributs sont nécessaires pour tracer un cercle
  • cx : la position du centre sur l'axe X

  • cy : la position du centre sur l'axe Y

  • r : son rayon

<circle cx="40" cy="40" r="30" fill="lightblue" 
  stroke="black" stroke-width="2"/>
<circle cx="60" cy="40" r="30" fill="none"
  stroke="red" stroke-width="2" stroke-dasharray="3,2"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c0.svg}

Ellipses

Pour les ellipses, il faut spécifier le rayon X et le rayon X. On a donc 4 attributs.
  • cx : la position du centre sur l'axe X

  • cy : la position du centre sur l'axe Y

  • rx : son rayon sur l'axe des X

  • ry : son rayon sur l'axe des Y

<ellipse cx="40" cy="40" rx="30" ry="10" 
  fill="lightgreen" stroke="red" stroke-width="2"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c1.svg}

Rectangle

Les rectangles sont définis par leurn position X et Y ainsi que leur largeur et hauteur. Cependant, il existe deux autres attributs permettant de faire des effets de coins arrondis
  • x : la position du coin supérieur gauche sur l'axe des X

  • y : la position du coin supérieur gauche sur l'axe des Y

  • width : hargeur du rectangle

  • height : hauteur du rectangle

  • rx : Rayon X de l'ellipse utilisée pour les coins arrondis

  • ry : Rayon Y de l'ellipse utilisée pour les coins arrondis

<rect x="5" y="5" width="60" height="20" 
fill="lightgreen" stroke="black" stroke-width="2"/>
<rect x="80" y="5" width="60" height="20" rx="5" ry="10"
fill="lightblue" stroke="black" stroke-width="5"/>
<rect x="160" y="5" width="60" height="20" rx="5" ry="5"
fill="lightyellow" stroke="black" stroke-width="2"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c2.svg}

Ligne

Une ligne est tout simplement composée de deux paires de coordonnées
  • x1 : Position de départ sur l'axe des X

  • y1 : Position de départ sur l'axe des Y

  • x2 : Position d'arrivée sur l'axe des X

  • y2 : Position d'arrivée sur l'axe des Y

<line x1="5" y1="5" x2="100" y2="25" stroke="black" stroke-width="1"/>
<line x1="5" y1="15" x2="100" y2="35" stroke="black" stroke-width="5"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c3.svg}

Polylines

Les polylines sont composées d'une suite de coordonnées représentant les divers points permettant de tracer une ligne. Tout est exprimé dans l'attribut points.
  • points : succession de paires de coordonnées permettant de tracer la ligne


La forme restera ouverte mais il est nécessaire de spécifier l'attribut fill en le mettant à “none” pour le remplissage.

<polyline points="5,5 20,15 35,5 50,15 65,5 80,15" 
  fill="none" stroke="red" stroke-width="2"/>
<polyline points="105,5 120,15 135,5 150,15 165,5 180,15"
  stroke="red" stroke-width="2"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c4.svg}

Polygones

Les polygones sont de simples formes fermées dont les points sont reliés par des lignes droites.
Leur syntaxe est identique à celle de polyline excepté que la forme est automatiquement fermée en reliant le dernier point tracé au premier.

<polygon points="5,5 20,15 35,5 50,15 65,5 80,15" 
fill="none" stroke="red" stroke-width="2"/>
<polygon points="100,10 140,10 140,5 160,15 140,25 140,20 100,20"
fill="lightyellow" stroke="black" stroke-width="2"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c5.svg}

Path

Path est l'élément central par excellence.
C'est celui qui permet de réaliser des formes courbes selon les méthodes de dessin propres au vectoriel.
L'attribut principal du path est d
  • d : succession commandes et de coordonnées permettant de définir le chemin à tracer


Cet attribut est une suite de commandes (une simple lettre) suivie de valeurs chiffrées (paramètres) donnant les indications de tracé.
D'une manière générale,
- les commandes en majuscule indiquent des coordonnées absolues.
- les commandes en minuscule indiquent des coordonnées relatives.

Voici donc une petite description des commandes que l'on peut trouver dans cet attribut
  • M / m : MoveTo, indique un point de départ.
    Cette commande signifie en gros que l'on a levé le crayon pour le reposer autre part et démarrer un nouveau tracé.
    M50,100 commence le tracé en x=50 et y=100.

  • L / l : LineTo, trace une ligne droite vers les coordonnées spécifiées.
    L20,60 trace une ligne du point courant vers x=20 y=60

  • H / h : HorizontalLineTo, trace une ligne horizontale vers le point spécifié.
    H60 trace un trait horizontal vers x=60

  • V / v : VerticalLineTo, trace une ligne verticale vers le point spécifié.
    v-50 trace un trait vertical de 50 pixels de long vers le haut.

  • Z / z : indique au moteur de rendu qu'il faut fermer la forme.\\Cette fermeture relie le point de départ à celui d'arrivée par une ligne droite.


Jusqu'ici, c'est relativement simple. Maintenant, voyons les courbes
  • C / c : CurveTo, Permet de tracer une courbe de Bezier cubique.
    Cette commande donne le point de destination et les coordonnées des deux points de contrôles nécessaires au traçage de l'arc.


Les paramètres sont x1,y1 x2,y2 x,y.

- x1 et y1 sont les coordonnées de contrôle du départ du tracé.

- x2 et y2 sont les coordonnées du point de contrôle de la fin du tracé

- x et y sont les coordonnées de la fin du tracé.
  • S / s : Smooth CurveTo, Continue un tracé en reprenant les référence du point précédent
    Cette commande est pratique pour continuer le tracé d'une courbe car elle reprend comme point de contrôle de départ du tracé les coordonnées “miroir” du point précédent.


Les paramètres sont x2,y2 x,y.

- x2 et y2 sont les coordonnées du point de contrôle de la fin du tracé

- x et y sont les coordonnées de la fin du tracé.

Exemple

<path d="M100,200 C100,100 250,100 250,200 S400,300 400,200" 
  stroke="red" stroke-width=2"/>

Le rendu de cette courbe apparait ci dessous en rouge. Les autres éléments montrent les différents points de contrôles et les commandes associées. Cet exemple vient tout droit du W3C. Il a été agrandi pour bien montrer les détails.
Les points gris sont les points de contrôles. Le point bleu est le point de contrôle implicitement calculé par l'utilisation de la commande S.

{attachment /85e03f3a1b25b62def1eadcce2b6726c6.svg}
  • Q/ q : Quadratic CurveTo, Permet de tracer une courbe de Bezier quadratique.
    Cette commande donne le point de destination et les coordonnées du point de contrôles.


Les paramètres sont x1,y1 x,y.

- x1 et y1 sont les coordonnées de contrôle du départ du tracé.

- x et y sont les coordonnées de la fin du tracé.
  • T / t : Smooth Quadratic CurveTo, Continue un tracé en reprenant les référence du point précédent
    Comme la commande S/s, elle permet de continuer un tracé existant en reprenant les informations du point de contrôle précédent. Les paramètres sont x,y.


- x et x1 sont les coordonnées de la fin du tracé.

Voici un autre exemple également en provenance du site du W3C.

 <path d="M200,300 Q400,50 600,300 T1000,300" 
  fill="none" stroke="red" stroke-width="5"  />

{attachment /85e03f3a1b25b62def1eadcce2b6726c7.svg}
  • A / a : Elliptical Arc, permet de tracer un arc de cercle.
    Plusieurs paramètres sont nécessaires à son traçage : rx,ry rotation large-arc-flag,sweep-flag x,y.


- rx et ry sont les rayons x et y de l'ellipse à tracer.

- rotation indique l'angle de rotation de l'ellipse sur l'axe des X.

- large-arc-flag précise quelle portion de l'arc doit être dessinée (0 pour petit, 1 pour grand)
- sweep-flag indique s'il faut tracer dans le sens des aiguilles d'une montre ou à l'inverse (0/1)
- x,y sont les coordonnées de fin de traçage de l'arc.

Pour y voir plus clair, voici une succession d'arcs, réalisés à partir de la même commande mais en faisant varier les paramètres de tracés

<g fill="none" stroke="red" stroke-width="2">
  <path d="M50,50 A50,50 0 0,0 100,100"/>
  <path d="M150,50 A50,50 0 0,1 200,100"/>
  <path d="M300,50 A50,50 0 1,0 350,100"/>
  <path d="M400,50 A50,50 0 1,1 450,100"/>
</g>

{attachment /85e03f3a1b25b62def1eadcce2b6726c8.svg}

Les plus observateurs auront repéré que j'ai utilisé une balise supplémentaire, <g>, qui permet de regrouper les éléments. C'est une part de ce qui fait la force du SVG.

Image

SVG supporte un tag bien utile permettant d'insérer des images externes avec un format différent

<image  x="0" y="0" width="80px" height="15px" 
  xlink:href="http://wiki.jeuweb.org/lib/images/smileys/fixme.gif" />

{attachment /85e03f3a1b25b62def1eadcce2b6726c9.svg}

Grouper et réutiliser

Le tag <g>

SVG permet donc de grouper des éléments.

Le premier avantage de ce système est qu'il permet de définir des attributs par défaut pour tous les sous éléments. Pour cela on utilise le tag <g>. Il est possible d'avoir autant de groupes et de sous groupes que l'on veut.

Les attributs “fils” peuvent bien sur être spécifiés de manière à remplacer ceux définis par le parent.

  <g fill="lightblue" stroke="black" stroke-width="1">
    <rect x="5" y="5" height="50" width="100"/>
    <circle cx="150" cy="30" r="20"/>
    <ellipse cx="220" cy="30" rx="40" ry="20" fill="lightgreen"/>
    <g fill="lightyellow">
      <rect x="5" y="65" height="50" width="100"/>
      <circle cx="150" cy="90" r="20"/>
      <ellipse cx="220" cy="90" rx="40" ry="20" fill="lightgreen"/>
    </g>
  </g>

{attachment /85e03f3a1b25b62def1eadcce2b6726c10.svg}

Les définitions <defs>

En plus des groupes, les fichiers SVG peuvent renformer des définitions encadrées par le tag <defs>. Ce tag comprends en général tous les éléments qui seront réutilisés dans graphique.

Les éléments placés entre les balises <defs> ne seront pas affichés mais ils pourront être référencés, dupliqués et transformés dans le corps du document. On utilisera pour cela les attributs transform e§t xlink:href

Transformations et réutilisations

La réutilisations s'effectue par le biais de la balise <use> et des attributs id et et xlink:href. Tout élément possédant un id peut être référencé. Il suffit de mettre dans l'attribut xlink:href un lien interne vers l'élément.

N'oubliez pas de mettre de spécifier l'attribut xmlns:xlink=“http://www.w3.org/1999/xlink” dans le tag svg principal pour bénéficier de cette fonctionnalité.

Prenons par exemple une flèche blanche sur un rond noir

<defs>
  <g id="arrowpic">
    <circle cx="10" cy="10" r="10" fill="black"/>
    <g id="arrow" fill="white">
      <rect x="7" y="8" height="8" width="6"/>
      <path d="M 10,3 L 3,9 L 17,9"/> 
    </g>
  </g>
</defs>
<use xlink:href="#arrowpic"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c11.svg}

<use> permet de prendre un groupe identifié par un id dans <defs> (ou ailleurs dans le document) et de l'afficher. Par défaut, l'élément s'affiche comme spécifié dans sa définition. Mais en utilisant l'attribut transform, il est possible de faire bien plus de choses.

transform est un attribut dont la valeur peut prendre plusieurs commandes
  • translate(x y) : place la copie créer à l'endroit indiqué par les paramètres x et y

  • scale (sx, sy) : redimensionne la copie en applicant les facteurs sx et xy à la dimension originale. Une valeur négative inverse l'image

  • rotate (a, cx cy) : effectue une rotation de l'objet d'un angle a en prenant pour centre de référence le point cx, cy

  • skewX(a) : déforme l'objet d'un angle a sur l'axe des x

  • skewY(a) : déforme l'objet d'un angle a sur l'axe des y

  • Matrix (a b c d e f) : utilise une matrice de transformation pour déformer l'objet. C'est une méthode assez complexe à appréhender qui regroupe toutes les autres transformations


Avec l'image donnée précédemment et quelques fonctions de transformation, on peut facilement construire quelque chose de plus intéressant en économisant les lignes.

<defs>
  <g class="arrowpic" id="arrowpic">
    <circle cx="10" cy="10" r="10" fill="black"/>
    <g id="arrow" fill="white">
      <rect x="7" y="8" height="8" width="6"/>
      <path d="M 10,3 L 3,9 L 17,9"/> 
    </g>
  </g>
</defs>
<!-- création d'un groupe que je vais placer en 0,10 -->
<g transform="translate(0,10)">
  <!-- Création d'un autre groupe nommé "arrowgroup" -->
  <g id="arrowgroup">
    <!-- réutilisation de la définition "arrowpic". -->
    <!-- Les éléments sont déplacés et tournés selon les besoins -->
    <use xlink:href="#arrowpic" transform="translate(0 0) rotate(315 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(20 0)" />
    <use xlink:href="#arrowpic" transform="translate(40 0) rotate(45 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(0 20) rotate(270 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(40 20) rotate(90 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(0 40) rotate(225 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(20 40) rotate(180 10 10)" />
    <use xlink:href="#arrowpic" transform="translate(40 40) rotate(135 10 10)" />
  </g>
</g>
<!-- réutilisation du gros groupe "arrowgroup" -->
<!-- Place une copie orientée différemment -->
<use xlink:href="#arrowgroup" transform="translate(80 10) rotate(45 30 30)" />

{attachment /85e03f3a1b25b62def1eadcce2b6726c12.svg}

Transformation d'Images

Les images provenant d'autres formats et intégrées au SVG peuvent aussi subir des transformations.

  <defs>
    <image id="fixme" x="0" y="0" width="80px" height="15px"
      xlink:href="http://wiki.jeuweb.org/lib/images/smileys/fixme.gif" />
  </defs>
  <use xlink:href="#fixme" transform="translate(-10 30) rotate(45 40 12.5)"/>
  <use xlink:href="#fixme" transform="translate(160 0) scale(-1 2)"/>
  <use xlink:href="#fixme" transform="translate(170 0) skewX(30)"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c13.svg}

C'est par exemple assez utile pour dupliquer une image selon différents angles. Les déformations engendrées par de telles transformations restent minimes.

Introduction du CSS

Comme expliqué plus haut, le SVG supporte le CSS pour la mise en forme
On peut utiliser un fichier externe ou recourir aux définition interne via la balise style.
Même les pseudo classes (comme :hover) sont accessibles.

<style>
  g.arrowblock {fill:gray;}
  g.arrow {fill:white;}
  g.arrowblock:hover {fill:black;}
  g.arrowblock:hover > g.arrow {fill:lightgreen;}
</style>
<defs>
  <!-- quelques définitions pour les graphiques-->
  <g class="arrowblock" id="arrowblock">
    <!-- l'élément ci dessous n'a pas d'attribut fill car il sera défini pas le CSS -->
    <rect x="0" y="0" height="20" width="20" rx="5" ry="5"/>
    <g class="arrow">
      <rect x="7" y="8" height="8" width="6"/>
      <path d="M 10,3 L 3,9 L 17,9"/> 
    </g>
  </g>
</defs>
<!-- Mise en place de la première flèche pointant à gauche -->
<use xlink:href="#arrowblock" transform="translate(5,5) scale(2,2) rotate(270 10 10)"/>
<!-- Mise en place de la 2e flèche pointant à droite -->
<use xlink:href="#arrowblock" transform="translate(55,5) scale(2,2) rotate(90 10 10)"/>

{attachment /85e03f3a1b25b62def1eadcce2b6726c14.svg}

L'utilisation des styles et des pseudo classes permet de faire quelques effets intéressants.
Une fois le SVG chargé, tout y est. Pas de précache à gèrer.
On peut agir sur d'autres attributs comme le contour par exemple.

<style>
  circle{stroke:black;fill:lightblue}
  .sw:hover{stroke-width:5px;}
  .st:hover{stroke-dasharray:2,6;}
</style>
<circle class="sw" cx="20" cy="20" r="15" />
<circle class="st" cx="55" cy="20" r="15" />

{attachment /85e03f3a1b25b62def1eadcce2b6726c15.svg}

Vaisseau

{attachment /85e03f3a1b25b62def1eadcce2b6726c16.svg}