IFT 1005 - Design et développement Web

7. SVG

Sébastien Roy, Université de Montréal

IFT 1005 - Design et développement Web

7. SVG

Sébastien Roy, Université de Montréal
6 mars 2023
 

Remerciements

Merci à Guy Lapalme et Louis Salvail pour avoir partager le matériel qu'ils ont monté pour IFT1005.

Le matériel de ce cours peut être réutilisé, sujet à la licence CC BY-SA 4.0.

Dessin sur les diapos! (oui, en SVG!)

Ces diapos sont "dynamiques"... Appuyez sur ces touches: et quand on dessine... Si les liens d'une diapo ne sont pas actifs, faites b!

Scalable Vector Graphics (SVG)

Exemple minimaliste


<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>

Et <canvas>?


<canvas id="myCanvas" width="100" height="100" style="background-color:lightgray">
</canvas>
<script>
  var c = document.getElementById("myCanvas");
  var ctx = c.getContext("2d");
  ctx.beginPath();
  ctx.strokeStyle = "#FF0000";ctx.arc(50, 50, 40, 0, 2 * Math.PI);
  ctx.strokeStyle = "green";
  ctx.lineWidth=4; ctx.fillStyle = "yellow";
  ctx.fill(); ctx.stroke();
</script>

Et <canvas>?

<canvas> est un api javascript pour faire du dessin dans une page web. En résumé...

Espace de visualisation


<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100" height="100">
...
</svg>
En pratique, on laisse souvent tomber le xmlsn= et xmlns:xlink=.

Espace de dessin (viewBox)

On peut choisir l'espace où on dessine avec l'attribut
viewBox="xmin ymin width height".

<svg width="100" height="100" class="bg-gray">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
<svg width="100" height="100" class="bg-gray" viewBox="0 0 400  400">
  <circle cx="200" cy="200" r="160" stroke="green" stroke-width="16" fill="yellow" />
</svg>

Ratio d'aspect (preserveAspectRatio)

Si l'espace SVG et la boite de dessin (viewBox) n'ont pas la même taile....

<svg width="200" height="100" class="bg-gray"
    viewBox="0 0 100 100" preserveAspectRatio="xMidYmid meet">
        ...
</svg>
<svg width="200" height="100" class="bg-gray"
    viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" >
        ...
</svg>

Définitions (<defs>)


<svg width="200" height="100" class="bg-gray">
  <defs>
    <circle id="blub" cx="50" cy="50" r="40" ... />
  </defs>
  <svg x="0" y="0" width="100" height="100" > <use href="#blub"/> </svg>
  <svg x="100"  y="0" width="100" height="100" > <use href="#blub"/> </svg>
</svg>

Éléments graphiques de base

Rectangle (rect)


    <svg width="200" height="100 ">
        <rect x="20" y="10" width="50" height="40" fill="red"/>
        <rect x="100" y="20" width="45" height="60" rx="10" ry="10"/>
    </svg>

Cercle (circle)


<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>

Ellipse (ellipse)


<svg width="200" height="100" class="bg-gray">
  <ellipse cx="100" cy="50" rx="80" ry="40" stroke="green" stroke-width="8" />
</svg>

Groupes (<g>)

On peut grouper des primitives, pour partager des attributs, des effets ou des transformations...

<svg height="100" width="200" >
    <g fill="red" stroke-width="10" stroke="orange">
        <circle cx="50" cy="50" r="40"/>
        <circle cx="150" cy="50" r="30"/>
    </g>
</svg>

Ligne (line)


<svg height="100" width="100">
    <line x1="10" y1="10" x2="90" y2="90" stroke-width="6" stroke="red" />
    <line x1="10%" y1="90%" x2="90%" y2="10%" stroke-width="6" stroke="blue" />
</svg>

Bouts de ligne (stroke-linecap)

Les bouts de lignes sont définis par stroke-linecap.

Les valeurs illustrées sont, dans l'ordre, butt, round, et square.

Ligne brisée (polyline)


<svg height="100" width="100">
    <polyline points="10,10 10,90 90,10 90,90" stroke-width="6" stroke="blue" fill="red"/>
</svg>
En fait, c'est un polygone non fermé...

Polygone (polygon)


<svg height="100" width="100">
    <polygon points="10,10 10,90 90,10 90,90" stroke-width="6" stroke="blue" fill="red"/>
</svg>

Joints de ligne (stroke-linejoin)

Les joints de lignes sont définis par stroke-linejoin.

Les valeurs illustrées sont, dans l'ordre, miter, round, et bevel.

Chemin (path)

Un chemin représente un contour qui peut être dessiné ou rempli. On peut aussi l'utiliser pour placer du texte, ou dans des animations. Toutes les primitices de bases s'expriment aussi avec path.

Chemin (path)

Un exemple...

<svg height="100" width="200">
  <g stroke-width="6" stroke="blue" fill="red">
      <polygon points="10,10 10,90 90,10 90,90"/>
      <path d="M 110 10 L 110,90 L 190,10 L 190,90 Z" fill="orange"/>
  </g>
</svg>

Chemin (path)

En minuscule, les coordonnées sont relatives plutôt qu'absolues...

Bézier cubique ( C et S )


<svg width="500" height="200" class="bg-gray" >
    <path d="M100,100 C100,10 350,10 250,100 S400,190 400,100"
                 fill="none" stroke="red" stroke-width="5" />
</svg>
    

Bézier quadratique ( Q et T )


<svg width="500" height="200" class="bg-gray" >
    <path d="M100,100 Q200,10 250,100 T400,100"
                     fill="none" stroke="red" stroke-width="5" />
</svg>

Arc d'ellipse ( A )


<svg width="200" height="200"  >
    <g fill="none" stroke-width="8" >
    <path d="M60,100 A50,50 0 0 0 140,100" stroke="red" />
    <path d="M60,100 A50,50 0 1 0 140,100" stroke="green" />
    <path d="M60,100 A50,50 0 0 1 140,100" stroke="blue" />
    <path d="M60,100 A50,50 0 1 1 140,100" stroke="purple" />
    </g>
</svg>

Attributs Core

Ces attributs peuvent être utilisé avec toutes les balises svg.

Attributs de présentation

Plusieurs attributs sont aussi des styles css. On les appelle des attributs de présentation. On peut donc utiliser directement l' attribut, ou le style.

<svg width="200" height="100">
    <circle cx="50" cy="50" r="40" fill="red"/>
    <circle cx="150" cy="50" r="40" style="fill:red;"/>
</svg>
    

Attributs de présentation

Voir la liste complète

Couleur

En SVG, une couleur n'est pas seulement un rgb... tout ce qui fonctionne en css est acceptable.

Couleur (quelques exemples)


<svg width="200" height="100">
    <circle cx="50" cy="50" r="40" fill="blue" stroke="red" stroke-width="10" />
    <circle cx="150" cy="50" r="40" fill="none" stroke="red"/>
</svg>
    

Couleur: gradient linéaire


On définit le gradient avec <defs> puis on y réfère avec le id.

<svg width="200" height="100" class="bg-gray">
    <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" stop-color=rgb(255,255,0) />
        <stop offset="100%" stop-color=rgb(255,0,0) />
    </linearGradient>
    <linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" stop-color=rgb(0,255,0) />
        <stop offset="100%" stop-color=rgb(0,0,255) />
    </linearGradient>
    </defs>
    <circle cx="50" cy="50" r="40" fill="url(#grad1)"/>
    <circle cx="150" cy="50" r="40" fill="url(#grad2)"/>
</svg>

    

Couleur: gradient radial


<svg height="100" width="200" >
  <defs>
    <radialGradient id="grad3" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
      <stop offset="0%" style="stop-color:rgb(255,255,255);
      stop-opacity:0" />
      <stop offset="100%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
    </radialGradient>
  </defs>
  <circle cx="50" cy="50" r="40" fill="url(#grad3)" />
  <rect x="100" y="10" width="80" height="80" rx="10" ry="10" fill="url(#grad3)" />
</svg>

pattern


<svg height="100" width="200" class="bg-gray">
<defs>
    <pattern id="pat1" patternUnits="userSpaceOnUse"
         x="0" y="0" width="20" height="20" viewBox="0 0 10 10" >
             <circle cx="5" cy="5" r="4" fill="red"/>
    </pattern>
  </defs>
  <ellipse fill="url(#pat1)" stroke="black" stroke-width="5"
          cx="100" cy="50" rx="80" ry="40" />
</svg>

Texte (text)

SVG!

<svg width="200" height="100" >
    <text x="50" y="50" fill="red" font-family="Verdana" font-size="64">
        S
        <tspan font-weight="bold" fill="orange" >V</tspan>
        G!
    </text>
</svg>

Texte (text)

On peut placer un texte le long d'un chemin...
Un peu de texte...

<svg width="300" height="100" >
    <path id="chemin" stroke="lightblue" stroke-width="6" fill="none"
        d="M 50,50 C 100,0 200,100 260,50"/>

    <text style="font: 24px sans-serif;">
        <textPath href="#chemin">Un peu de texte...</textPath>
    </text>
</svg>

Image (image)


<svg width="100" height="100">
    <image x="10" y="10" width="80" height="80" xlink:href="img/lovelogo.png"/>
</svg>

Filtres ( filter )


<svg height="140" width="240">
  <defs>
    <filter id="f3" x="-20%" y="-20%" width="150%" height="150%">
      <feOffset result="offOut" in="SourceAlpha" dx="5" dy="5" />
      <feGaussianBlur result="blurOut" in="offOut" stdDeviation="6" />
      <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
    </filter>
  </defs>
  <circle cx="90" cy="70" r="30" fill="red" filter="url(#f3)" />
  <rect x="20" y="20" width="60" height="60" fill="yellow" filter="url(#f3)" />
</svg>

Clic?

On peut associer un lien à n'importe quel élément...

<svg width="100" height="100" class="bg-gray">
    <a xlink:href="http://www.umontreal.ca" target="_blank">
        <circle cx="50" cy="50" r="40" fill="green"/>
    </a>
</svg>

Transformations ( attribut transform )

On peut transformer le système de coordonées...

<svg width="100" height="100" class="bg-gray">
    <rect x="20" y="20" width="60" height="60" fill="red"
             transform="rotate(45 50 50)"/>
</svg>
Ici, c'est rotate(angle cx cy).

Transformations ( attribut transform )

On peut les combiner...

 transform="translate(80, 80) scale(1.5, 1.5) rotate(45)"
    

Animation ( animate )

On ajoute un élément animate dans l'élément.

<svg width="100" height="100" >
    <rect x="20" y="20" width="60" height="60" fill="red">
        <animate attributeName="height" from="50" to="70" dur="2s"
                    repeatCount="indefinite" />
    </rect>
</svg>
    

Animation ( animate )

On peut fournir des valeurs (keyframe) avec value

<svg width="100" height="100" class="bg-gray">
    <rect x="20" y="20" width="60" height="60" fill="red">
        <animate attributeName="opacity" values="0;1;0" dur="3s"
                repeatCount="indefinite" />
    </rect>
</svg>
    

Animation ( animate )

On peut fournir des temps (entre 0 et 1) avec keyTimes

<svg width="100" height="100" class="bg-gray">
    <rect x="20" y="20" width="60" height="60" fill="red">
        <animate attributeName="opacity" dur="3s" repeatCount="indefinite"
            values="0;1;0" keyTimes="0;0.2;1" />
        <animate attributeName="fill" dur="3s" repeatCount="indefinite"
           values="red;green;red" keyTimes="0;0.2;1" calcMode="discrete" />
    </rect>
</svg>

    

Animation (animateTransform)

Pour animer les transformations (translation, scale, rotation).

<svg width="100" height="100" class="bg-gray">
    <rect x="20" y="20" width="60" height="60" fill="red"
                    transform="rotate(45 50 50)">
        <animateTransform attributeName="transform" type="rotate" dur="15s"
                from="0 50 50" to="360 50 50" repeatCount="indefinite"  />
    </rect>
</svg>

Animation de texte

Pour se déplacer le long d'un chemin...
Un peu de Texte...

<svg width="400" height="100" class="bg-gray">
    <path id="chemin2" stroke="lightblue" stroke-width="6" fill="none"
        d="M 50,50 C 100,0 200,100 260,50 S 200,130 370,80"/>
    <text style="font: 24px sans-serif;">
      <textPath href="#chemin2" startOffset="0">Un peu de Texte...
          <animate attributeName="startOffset" values="0%;100%;0%" dur="10s" repeatCount="indefinite"/>
      </textPath>
    </text>
</svg>

Animation (animateMotion)

Pour déplacer le long d'un chemin...

<svg width="400" height="100" >
    <path id="chemin3" stroke="lightblue" stroke-width="6" fill="none"
        d="M 50,50 C 100,0 200,100 260,50 S 200,130 370,80"/>
    <rect x="-10" y="-10" width="20" height="20" fill="red">
        <animateMotion dur="6s" repeatCount="indefinite" rotate="auto" >
           <mpath href="#chemin3"/>
        </animateMotion>
    </rect>
</svg>

Animation (animateMotion)

Pour déplacer une liste de points (polyline par exemple)...

<path id="chemin4" stroke="blue" stroke-width="6" fill="none"
        d="M 50,50 C 100,0 200,100 260,50 Q 200,130 370,80">
    <animate dur="3s" repeatCount="indefinite" attributeName="d"
       to="M 50,80 C 100,100 100,80 260,50 Q 100,130 370,80"/>
</path>

Bon SVG!