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…