svg : on dessine

Dans ce troisième article consacré au SVG je vais un peu détailler les possibilités de dessins. J’ai déjà présenté des bases dans cet article. Je vais maintenant aller plus loin et montrer les belles possibilités qui nous sont offertes.

Des lignes

Simple ligne

La base du dessin c’est la ligne et SVG est bien équipé dans le domaine. On a vu qu’on dispose de la balise line. Par défaut on a stroke: none, ce qui signifie qu’une ligne n’est pas visible par défaut ! Donc si vous prévoyez ce code :

<line x1="20" y1="20" x2="100" y2="150"/>

Vous ne verrez rien…

Donc il faut au minimum définir la couleur (stroke) :

<line x1="20" y1="20" x2="100" y2="150" stroke="red" />

On définit le point d’origine (x1 et y1) et le point d’arrivée (x2 et y2). Je rappelle que l’origine des axes se trouve dans le coin supérieur gauche (ce qui est classique).

On peut ensuite styliser cette ligne en changeant l’épaisseur et la continuité (pointillés) :

<svg height="400" width="400">
    <style>
        line {
            stroke: blue;
            stroke-dasharray: 8, 4;
            stroke-width: .2rem;                
        }
    </style>
    <line x1="20" y1="20" x2="100" y2="150"/>
</svg>

Les deux valeurs pour les pointillés repèrent la partie pleine et la partie vide (gap).

On peut aussi jouer sur l’opacité d’une ligne avec la propriété stroke-opacity :

<line x1="20" y1="50" x2="100" y2="50" style="stroke: blue; stroke-width: 25;"/>
<line x1="20" y1="20" x2="100" y2="120"style="stroke-opacity: 0.4; stroke: red; stroke-width: 25;"/>

On peut faire beaucoup de choses avec des lignes mais ça devient vitre laborieux.

Polyligne

Si on aune succession de lignes plutôt que de dessiner les lignes les unes après les autres on utilise une polyligne :

<svg height="400" width="400">
    <style>
        polyline {
            stroke: green;
            stroke-width: 10;
            fill: none;               
        }
    </style>
    <polyline points="60 140, 100 50, 55 100, 55 10, 25 100"/>
</svg>

J’ai prévu sans remplissage () sinon on obtient ce résultat :

On peut évidemment choisir aussi la couleur de remplissage en fixant la couleur au lieu de none.

Terminaison de ligne et liaison

Quand on trace des lignes (et polylignes) les extrémités sont avec des angles à 90° :

On peut utiliser la propriété stroke-linecap (la valeur par défaut est butt) pour changer ce comportement :

<svg height="400" width="400">
    <style>
        line {
            stroke: purple;
            stroke-width: 20;                
        }
    </style>
    <line x1="20" y1="20" x2="140" y2="20" stroke-linecap="butt"/>
    <line x1="20" y1="50" x2="140" y2="50" stroke-linecap="round"/>
    <line x1="20" y1="80" x2="140" y2="80" stroke-linecap="square"/>
</svg>

Vous pouvez remarquer que les valeurs round et square prolongent la ligne au-delà des valeurs de référence.

Pour la jonction entre deux lignes on a la propriété stroke-linejoin :

<svg height="400" width="400"> 
    <style> polyline { 
        stroke: green; 
        stroke-width: 10;
        stroke-linecap: round;
        stroke-linejoin: round;
        fill: none; } 
    </style> 
    <polyline points="60 140, 100 50, 55 100, 55 10, 25 100"/>
</svg>

Des formes

Rectangle

J’ai déjà montré comment dessiner un rectangle dans le premier article. On peut évidemment styliser à loisir :

<svg height="400" width="400"> 
    <rect x="20" y="20" width="50" height="90" style="fill-opacity: 0.3"/>
    <rect x="40" y="10" width="80" height="40" style="fill: none; stroke: black;"/>
    <rect x="10" y="40" width="125" height="100" style="fill: #0000ff; stroke: blue; stroke-width: 10; stroke-opacity: 0.2; fill-opacity: 0.3"/>
    <rect x="50" y="70" width="135" height="50" style="fill: yellow; fill-opacity: 0.5; stroke: green; stroke-width: 2; stroke-dasharray: 5 2"/>
</svg>

 

On peut arrondir les coins en précisant le rayon :

<rect x="10" y="10" width="125" height="70" rx="20" style="fill: none; stroke: rgb(118, 19, 163); stroke-width: 10"/>
<rect x="10" y="110" width="125" height="70" rx="20" ry="40" style="fill: none; stroke: rgb(16, 207, 80); stroke-width: 10"/>

Cercle et ellipse

J’ai également montré comment tracer cercles et ellipses, voici un exemple :

<circle cx="50" cy="50" r="40" style="stroke: rgb(160, 189, 32); stroke-width: 7; fill: none;"/>
<circle cx="70" cy="80" r="60" style="stroke: rgb(201, 20, 20); stroke-width: 7; fill: none; stroke-opacity: 0.4"/>
<ellipse cx="130" cy="80" rx="80" ry="40" style="fill: blue; fill-opacity: 0.2"/>

Polygone

Pour un polygone on définit tous les points :

<polygon points="100,10 40,198 190,78 10,78 160,198" style="fill: rgb(163, 126, 194); stroke: blue; stroke-width: 7"/>

On gère évidemment tous les styles concernant le trait et le remplissage comme on l’a vu plus haut.

On peut modifier la règle de remplissage :

<polygon points="100,10 40,198 190,78 10,78 160,198" style="fill-rule: evenodd; fill: rgb(163, 126, 194); stroke: blue; stroke-width: 7"/>

Les chemins (path)

Les bases

Toutes les formes de base vues ci-dessus sont pratiques et doivent être utilisées en priorité. mais arrive un moment où elles ne sont pas suffisantes, on peut alors utiliser un chemin (path).

Une chemin est une succession de lignes , d’arcs et de courbes. On peut définir le trait comme on l’a déjà vu. Voici un premier exemple :

<path d="M 10 10 L 200 30" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

Un chemin doit commencer par un moveto (M) suivi des coordonnées de départ. Imaginez cela comme le fait de placer le stylo sur le point. Ensuite on place des lineto (L) avec des coordonnées, là on déplace le stylo.

On place autant de lineto qu’on veut :

<path d="M 10 10 L 200 30 L 200 80" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

Si vous insérez un nouveau moveto vous démarrez un sous-chemin :

<path d="M 10 10 L 200 30 M 220 30 L 200 80" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

Vous pouvez provoquer la fermeture du chemin avec un closepath (Z) :

<path d="M 10 10 L 200 30 L 200 80 Z" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

On a vu jusque la des valeurs absolues pour les coordonnées de déplacement, on peut aussi utiliser des valeurs relative en utilisant des minuscules :

<path d="M 10 10 L 200 30 m 20 0 l -20 50" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

Les raccourcis

On peut simplifier la syntaxe pour les lignes horizontales (H) et verticales (V) :

<path d="M 30 20 h 200 v 60 h -200 z" style="stroke-width: 10; stroke: rgb(231, 163, 37); fill: none;"/>

Les arcs elliptiques

Les arcs elliptiques sont des morceaux d’ellipses. Voici un exemple :

<path d="M 320 150 A 150 120, 0, 1, 0, 2 152" style="stroke-width: 4; stroke: red; fill: none;"/>

On utilise l’abréviation A suivie des deux rayons (x et y), puis de la rotation de l’axe x, puis d’autres valeurs qu’il serait laborieux de décrire. Je suppose que vous n’allez jamais dessiner un arc elliptique directement en partant du code ! On atteint ici les limites entre le fait de vouloir tout coder directement et utiliser un éditeur graphique.

Les courbes de Bézier

Vous utiliserez plus souvent des courbes de Bézier que des arcs elliptique, parce que vous pourrez plus facilement dessiner tout ce que vous voulez. Là ça devient carrément périlleux de se lancer dans le codage direct et on passe obligatoirement par un éditeur graphique.

Vous pouvez utiliser Inkscape comme je vous l’ai conseillé, ou un des nombreux éditeurs en ligne comme SVG-edit :

Voici un fichier SVG créé en quelques clics avec Inkscape :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   id="svg8"
   version="1.1"
   viewBox="0 0 159 106"
   height="400"
   width="600">
  <defs
     id="defs2" />
  <metadata
     id="metadata5">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     transform="translate(0,-191)"
     id="layer1">
    <path
       id="path836"
       d="m 15.9,276 c 0,0 -21.2,-48 15.9,-43 37.1,6 31.8,16 47.7,6 15.9,-11 79.5,32 31.5,37 -47.4,5 -95.1,0 -95.1,0 z"
       style="fill:#8bc200;stroke:#8a0000;stroke-width:1.59;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
  </g>
</svg>

Un exemple

Voici le code d’un exemple récupéré dans une librairie en ligne que j’ai nettoyé de plein de choses inutiles :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <path
    d="M432,8H80C66.766,8,56,18.766,56,32v456c0,13.234,10.766,24,24,24h352c13.234,0,24-10.766,24-24V32    
    C456,18.766,445.234,8,432,8z"
    style="fill:#FF4F19;" />
    <path
    d="M95.781,8H80C66.766,8,56,18.766,56,32v456c0,13.234,10.766,24,24,24h15.781V8z"
    style="fill:#E3001E;" />
  <path
    d="M400,0h-80c-4.418,0-8,3.582-8,8v119.996c0,2.883,1.547,5.543,4.055,6.961 
    c2.508,1.422,5.586,1.391,8.063-0.102L360,113.325l35.883,21.531c1.266,0.762,2.695,1.141,4.117,1.141    
    c1.359,0,2.719-0.344,3.945-1.039c2.508-1.418,4.055-4.078,4.055-6.961V8C408,3.582,404.418,0,400,0z"
    style="fill:#5D647F;" />
  <path
    d="M96,480c-4.422,0-8-3.582-8-8V48c0-4.418,3.578-8,8-8s8,3.582,8,8v424 C104,476.418,100.422,480,96,480z"
    style="fill:#C10019;" />
  <path
    d="M355.781,344h-0.572c-0.071-0.272-0.084-0.545-0.17-0.816L309.76,199.801 
    c5.679-0.948,10.021-5.85,10.021-11.801c0-6.629-5.375-12-12-12h-64c-6.625,0-12,5.371-12,12c0,5.951,4.343,10.853,10.021,11.801    
    l-45.279,143.383c-0.086,0.271-0.1,0.544-0.17,0.816h-0.572c-6.625,0-12,5.371-12,12s5.375,12,12,12h32c6.625,0,12-5.371,12-12    
    c0-5.951-4.342-10.853-10.021-11.801L238.665,316h74.231l8.905,28.199c-5.678,0.948-10.021,5.85-10.021,11.801    
    c0,6.629,5.375,12,12,12h32c6.625,0,12-5.371,12-12S362.406,344,355.781,344z M248.77,284l26.269-83.184    
    c0.086-0.271,0.1-0.544,0.17-0.816h1.144c0.071,0.272,0.084,0.545,0.17,0.816L302.792,284H248.77z"
    style="fill:#FFCD00;" />
</svg>

On voit que le dessin est composé de 5 chemins, voici la vue éclatée :

On voit qu’on pourrait simplifier le fichier en utilisant plutôt un rectangle aux coins arrondis pour la grosse partie orange, on peut donc remplacer le premier chemin par ce code :

<rect
  style="fill:#ff4f19;"
  id="rect28"
  width="396"
  height="506"
  x="55"
  y="8"
  ry="25.1"
  rx="27.1" />

On peut aussi se contenter d’un simple trait pour la partie verticale fine.

Par contre les 3 autres éléments nécessitent un chemin.

C’est l’inconvénient des éditeurs, ils ne permettent pas toujours de faire des choses simples mais on leur pardonne parce qu’ils sont vraiment performants !

Le fichier fait moins de 2Ko ce qui est très peu. Et on dispose d’une image qui peut s’adapter à toutes les résolutions !

La même image en PNG au format 512*512 fait 5Ko et elle est bien moins adaptable :

En plus il est impossible d’agir avec du style ou un script sur des éléments de l’image. On doit la prendre globalement telle qu’elle est.

On a donc tout intérêt à utiliser le format SVG !

Un autre exemple

Sur le même site j’ai trouvé un joli crayon, voilà le code nettoyé :

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.096 512.096" >
  <path style="fill:#E6BE94;" d="M296.158,0h-80c-4.418,0-8,3.582-8,8v376l44.282,125.466c1.238,3.507,6.198,3.507,7.435,0
    L304.158,384V8C304.158,3.582,300.576,0,296.158,0z"/>
  <path style="fill:#FFD788;" d="M255.939,280v232h0.544c1.431-0.119,2.82-0.909,3.393-2.534L304.158,384V280H255.939z"/>
  <path style="fill:#FFCD00;" d="M296.158,0h-80c-4.418,0-8,3.582-8,8v376c0-8.837,7.164-16,16-16s16,7.163,16,16
    c0-8.837,7.164-16,16-16s16,7.163,16,16c0-8.837,7.164-16,16-16s16,7.163,16,16V8C304.158,3.582,300.576,0,296.158,0z"/>
  <path style="fill:#FFCD00;" d="M240.158,384c0-8.837,7.164-16,16-16c8.092,0,14.711,6.028,15.781,13.826V0h-32v381.826
    C240.037,382.544,240.158,383.255,240.158,384z"/>
  <path style="fill:#FF9100;" d="M208.158,384c0-8.837,7.164-16,16-16c8.092,0,14.711,6.028,15.781,13.826V0h-24
    c-4.418,0-8,3.582-8,8v373.826C208.037,382.544,208.158,383.255,208.158,384z"/>
  <path style="fill:#FFE671;" d="M303.719,384c0-8.837-7.164-16-16-16c-8.092,0-14.711,6.028-15.781,13.826V0h24
    c4.418,0,8,3.582,8,8v373.826C303.84,382.544,303.719,383.255,303.719,384z"/>
  <path style="fill:#5C546A;" d="M233.57,456l18.871,53.466c1.238,3.507,6.198,3.507,7.436,0L278.746,456H233.57z"/>
  <path style="fill:#868491;" d="M255.939,512.031c1.624,0.091,3.288-0.724,3.937-2.565L278.746,456h-22.808L255.939,512.031
    L255.939,512.031z"/>
</svg>

Il a été créé avec 8 chemins :

On pourrait composer ce crayon de multiples autres façons avec sans doute une amélioration du code mais le gain en serait au final pas tellement significatif.

Conclusion

Pour créer une image SVG il est donc incontournable d’utiliser un éditeur spécialisé comme Inkscape, ou un des multiples proposés en ligne, mais aussi de connaître la syntaxe pour apporter des modifications, nettoyer le code…

Laisser un commentaire