31/10/2018 Tech
SVG : Comprendre le système de coordonnées
Introduction
La balise svg crée une zone de dessin aux dimensions illimitées, c’est ce que l’on appelle le canvas, dont l’utilisateur ne verra qu’une partie, un rectangle délimité par les attributs width et height de la balise. C’est ce rectangle que l’on appelle le viewport.
Il faut voir ça comme un écran de télévision, celui-ci délimitant une zone d’affichage convenue, alors qu’un plateau de télévision est bien sur plus vaste.
Sans plus d’informations fournies par divers attributs, un système de coordonnées est mis en place, avec pour origine le coin supérieur gauche du viewport.
Maintenant, on va voir comment jouer avec ces coordonnées.
L’attribut viewbox en SVG
Pas de teasing, tout va se faire grâce à l’attribut viewbox. Si aucune valeur n’est précisée, le viewport ne sera pas modifié, et donc le système de coordonnées ne changera pas. Viewbox prend en valeur 4 paramètres :
viewBox = " <min-x> <min-y> <width> <height> "
Ces 4 paramètres n’ont pas d’unités et vont permettre de définir un rectangle qui va redéfinir le système de coordonnées du viewport. Et c’est là que les choses deviennent intéressantes. L’échelle (scale) pourra être modifiée et être supérieure ou inférieure à la valeur de base 1:1, mais toujours de façon à faire rentrer, ou plutôt à contraindre, le viewbox dans le viewport.
Petit aparté visuel sur les bordures des exemples qui vont suivre, pour mieux comprendre mes propos :
- Le cadre gris foncé représente les limites du svg.
- Le cadre jaune représente lui le viewbox, c’est le contour d’un rectangle qui fait toujours les dimensions du viewbox. Son contour est de 6px, 3 à l’extérieur, et 3 à l’intérieur de l’élément rect.
- Par ailleurs, un lien vers codepen est présent sur chacune des images pour permettre de vraiment visualiser le résultat en svg.
Modification de l’échelle de façon homothétique
![svg1](https://www.ekino.com/uploads/2018/10/svg1.png “”) |
<svg width="150" height="150" viewbox="0 0 150 150" />
Pas de surprise, c’est l’exemple de base, le viewbox est précisé et fait les mêmes dimensions que le viewport. Le rond bleu a bien un diamètre de 100, et le rond rose n’est pas visible.
|
![svg2](https://www.ekino.com/uploads/2018/10/svg2.png “”) |
<svg width="150" height="150" viewbox="0 0 300 300" />
Cette fois le viewbox représente deux fois le viewport. Il en résulte donc une surface d’affichage deux fois fois plus large, mais toujours dans le même viewport. L’échelle est donc inférieure, ici 1:2, les cercles apparaissent deux fois plus petits, et le rose est cette fois visible.
|
![svg3](https://www.ekino.com/uploads/2018/10/svg3.png “”) |
<svg width="150" height="150" viewbox="0 0 100 100" />
Cette fois-ci, le viewbox est inférieur au viewport. L’échelle est aussi modifiée à 3:2, le rond bleu prend cette fois toute la place disponible, soit un diamètre de 100 * 3 / 2 = 150, ce qui correspond bien aux largeur et hauteur du viewport.
|
Ces trois exemples ont été faits en précisant un viewbox homothétique au viewport, maintenant, essayons en changeant cela.
Modification de l’échelle de façon non homothétique
![svg4](https://www.ekino.com/uploads/2018/10/svg4.png “”) |
<svg width="150" height="150" viewbox="0 0 150 100" />
L’échelle sur l’axe x n’est pas modifiée, puisque la largeur du viewbox est la même que celle du viewport.
|
![svg5](https://www.ekino.com/uploads/2018/10/svg5.png “”) |
<svg width="150" height="150" viewbox="0 0 200 300" />
Sur cet exemple, l’échelle a été modifiée, puisque ni la largeur, ni la hauteur du viewbox ne correspondait au viewport. Par contre, le ratio entre l’axe x et y reste le même, le rond n’est toujours pas déformé, et on peut se rendre compte que cette fois, le viewbox est centré horizontalement dans le viewport.
|
La translation
Jusqu’à maintenant, on n’avait pas modifié min-x
et min-y
. Et bien c’est parti!
![svg6](https://www.ekino.com/uploads/2018/10/svg6.png “”) |
<svg width="150" height="150" viewbox="50 -50 150 150" />
Préciser une valeur autre que 0 à
|
![svg7](https://www.ekino.com/uploads/2018/10/svg7.png “”) |
<svg width="150" height="150" viewbox="50 50 300 300" />
Dans ce cas, et comme déjà vu un peu plus haut, la zone d’affichage est deux fois plus grande, vu que l’échelle est devenue plus petite. La translation est également là, mais paraît deux fois moins importante. Visuellement, c’est le cas.
|
![svg8](https://www.ekino.com/uploads/2018/10/svg8.png “”) |
<svg width="150" height="150" viewbox="75 0 150 300" />
Pour ce dernier exemple, je vais cumuler ce que l’on a vu jusqu’à maintenant. La hauteur du viewbox est deux fois celle du viewport, donc l’échelle est inférieure. En revanche, la largeur du viewbox est la même que celle du viewport, et comme l’attribut preserveAspectRatio n’est pas précisé, le ratio entre l’axe x et l’axe y est préservé. Le viewbox fait donc visuellement 75 pixels de large et est centré dans le viewport. Ensuite, il y a une translation de 75 sur l’échelle du viewbox, soit visuellement de 37,5. Le point d’origine de la viewbox se retrouve donc maintenant confondu avec celui du viewport
|
Ce dernier exemple utilise une translation pour empêcher de centrer le viewbox dans le viewport. On va voir qu’il y a plus simple pour arriver au même résultat.
PreserveAspectRatio
Cet attribut prend deux valeurs en paramètre (le deuxième est facultatif) et n’est pas interprété si l’attribut viewbox est absent :
preserveAspectRatio = " <align> [<meetOrSlice>] "
Le paramètre align
<align>
peut prendre comme valeur l’une des dix suivantes : none
, xMinYMin
, xMinYMid
, xMinYMax
, xMidYMin
, xMidYMid
, xMidYMax
, xMaxYMin
, xMaxYMid
, xMaxYMax
. À part none
, ces valeurs vont permettre d’aligner le viewbox dans le viewport.
none | ![svg9](https://www.ekino.com/uploads/2018/10/svg9.png “”) |
<svg width="150" height="150" viewbox="0 0 300 150" preserveAspectRatio="none" />
|
xMinYMin | ![svg10](https://www.ekino.com/uploads/2018/10/svg10.png “”) |
<svg width="150" height="150" viewbox="0 0 300 150" preserveAspectRatio="xMinYMin" />
Dans cet exemple, nous avons défini un viewbox deux fois plus large que haut. Sans preserveAspectRatio, le viewbox serait centré verticalement dans le viewport, comme on l’a vu précédemment. Mais ici, en précisant comme valeur d’alignement
|
xMaxYMin | ![svg11](https://www.ekino.com/uploads/2018/10/svg11.png “”) |
<svg width="150" height="150" viewbox="0 0 150 300" preserveAspectRatio="xMaxYMin" />
Cette fois, c’est la hauteur qui est supérieure à la largeur. On pourrait s’attendre à ce que le viewbox soit centré horizontalement, mais la valeur
|
xMidYMax | ![svg12](https://www.ekino.com/uploads/2018/10/svg12.png “”) |
<svg width="150" height="150" viewbox="0 0 150 300" preserveAspectRatio="xMidYMax" />
En reprenant l’exemple précédent, mais en précisant un preserveAspectRatio à
|
Pas la peine d’illustrer tous les cas de figure, les exemples sont suffisamment parlants concernant l’alignement en “Min” ou en “Max”. Par contre, l’intérêt de “Mid” est plutôt limité pour le moment.
Mais c’est là que <meetOrSlice>
va rentrer en jeu.
Le paramètre meetOrSlice
<meetOrSlice>
, comme son nom l’indique peut avoir deux valeurs différentes : meet
, qui est la valeur par défaut, ou slice
, la valeur à laquelle nous allons nous intéresser.
Jusqu’à maintenant, on a vu que le viewbox était contraint dans le viewport par la plus grande valeur entre le <width>
et le <height>
de l’attribut viewbox. slice
permet de changer cela et d’utiliser la plus petite valeur.
Si le viewbox n’est pas homothétique au viewport, une partie du viewbox ne sera donc pas visible.
xMinYMin slice | ![svg13](https://www.ekino.com/uploads/2018/10/svg13.png “”) |
<svg width="150" height="150" viewbox="0 0 300 150" preserveAspectRatio="xMinYMin slice" />
Dans ce cas, le viewbox est plus long que le viewport, et le paramètre
|
xMaxYMin slice | ![svg14](https://www.ekino.com/uploads/2018/10/svg14.png “”) |
<svg width="150" height="150" viewbox="0 0 300 150" preserveAspectRatio="xMaxYMin slice" />
|
xMidYMin slice | ![svg15](https://www.ekino.com/uploads/2018/10/svg15.png “”) |
<svg width="150" height="150" viewbox="0 0 300 150" preserveAspectRatio="xMidYMin slice" />
Troisième cas de figure,
|
xMidYMid slice | ![svg16](https://www.ekino.com/uploads/2018/10/svg16.png “”) |
<svg width="150" height="150" viewbox="0 0 150 300" preserveAspectRatio="xMidYMid slice" />
Dernier exemple : cette fois, le viewbox a une hauteur supérieure au viewport.
|
Conclusion
Ça y est, nous voilà à la fin de cet article.
Bien comprendre les coordonnées est important et permet de plus facilement travailler avec les SVGs exportés par différents logiciels. Cela permet aussi de résoudre des problématiques simples comme :
- Mon SVG est bien présent dans la page, mais rien ne s’affiche.
- Je n’ai qu’une partie du SVG d’affichée, et en plus celle-ci à l’air d’être zoomée.
Un peu de lecture complémentaire pour finir :
- La spec officielle du W3C (en)
- SVG Viewport and View Box de Jakob Jenkov (en)
- How to Scale SVG de Amelia Bellamy-Royds (en)
- Understanding SVG Coordinate Systems & Transformations (Part 1) – The viewport, viewBox, & preserveAspectRatio de Sara Soueidan (en)