HTML5 – Balises pour graphisme

LEÇON

 

SVG

SVG = (en anglais) Scalable Vector Graphics ou "Graphique Vectoriel Adaptable".

Depuis HTML5 on peut utiliser SVG pour dessiner des éléments graphiques à la volée directement dans une page web via des balises. Ces dessins peuvent être statiques ou animés. Quelques exemples de l'utilisation de la balise <svg>...

 

Exemple 1 : un rond tout seul

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
    </head>
    <body style="background-color:gray;">

    <svg width="600" height="600">
      <circle cx="300" cy="300" r="280" fill="gold" />
    </svg>

    </body>
</html>

 

Exemple 1 et exemple 2 donnent le même résultat, mais l'exemple 2 est préférable car il est toujours mieux d'exprimer via CSS les attributs qui contrôlent la mise en page (le style) des éléments (couleur, etc).

Exemple 2 : un rond tout seul (style via inline CSS)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
    </head>
    <body style="background-color:gray;">

    <svg width="600" height="600">
      <circle cx="300" cy="300" r="280" style="fill:gold" />
    </svg>

    </body>
</html>

 

Exemple 3 : un carré avec une bordure (styles via feuille de CSS interne)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
        <style>
        body { background-color:gray; }
        polygon { fill:skyblue;
                  stroke:white;
                  stroke-width:4; }
        </style>
    </head>
    <body>

    <svg width="200" height="200">
      <polygon points="20,20 180,20 180,180 20,180"/>
    </svg>

    </body>
</html>

 

Exemple 4 : plusieurs carrés de différentes tailles et couleurs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
        <style>
        body { background-color:gray; }
        polygon { stroke:white;
                  stroke-width:4; }
        polygon.bleu {fill:skyblue; }
        polygon.orange {fill:darkorange; }
        </style>
    </head>
    <body>

    <svg width="960" height="200">
      <polygon points="20,20 180,20 180,180 20,180" class="bleu" />
      <polygon points="220,20 350,20 350,150 220,150" class="orange" />
      <polygon points="390,20 490,20 490,120 390,120" class="bleu" />
      <polygon points="530,20 600,20 600,90 530,90" class="orange" />
      <polygon points="640,20 680,20 680,60 640,60" class="bleu" />
    </svg>

    </body>
</html>

 

Génération de code SVG via un logiciel (par le développeur avant publication sur le web)

Les dessins SVG peuvent être créées "à la main" via un éditeur de texte. Mais il y a aussi l'option d'utiliser un logiciel pour générer le HTML depuis une interface graphique (ne s'applique pas à la génération dynamique évoquée ci-dessus bien sûr). Par exemple :

  • Inkscape (open source, gratuit)
  • Adobe Illustrator (payant)

 

SVG et PHP

D'après les leçons précédentes, on sait afficher des images jpg, png, etc dans nos pages web, en avant plan ou en tant que fond. On sait également intégrer les vidéos dans nos pages web. Avant l'existence de HTML5, les possibilités pour le graphisme vectoriel étaient très limitées - en gros, il existaient les animations Flash (solution propriétaire).

Maintenant, avec SVG, on a non seulement la possibilité de faire du graphisme vectoriel, mais ceci via du code HTML. Ce point est important car ça évoque forcement la possibilité de générer le code HTML côté serveur (via PHP par exemple, comme on sait déjà faire) et ainsi générer des images côté serveur...

 

Exemple 5 : plusieurs carrés de différentes tailles et couleurs - code généré via PHP

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
        <style>
        body { background-color:gray; }
        polygon { stroke:white;
                  stroke-width:4; }
        polygon.bleu {fill:skyblue; }
        polygon.orange {fill:darkorange; }
        </style>
    </head>
    <body>

    <svg width="960" height="200">

<?php
    $decalage = 0;
    for($i=0; $i<5; $i++)
    {
      $taille = 200 - (30 * $i);
      $top = 20;
      $bottom = $taille - 20;
      $left = $decalage + 20;
      $right = $decalage + $taille - 20;
      $classe = ($i % 2 == 1 ? "orange" : "bleu" );

      echo '<polygon points="'
           . $left . ',' . $top . ' '
           . $right . ',' . $top . ' '
           . $right . ',' . $bottom . ' '
           . $left . ',' . $bottom . '" '
           . 'class="' . $classe . '" />';

      $decalage = $decalage + $taille;
    }
?>

    </svg>

    </body>
</html>

 

Si on peut générer du SVG à la volée côté serveur, on peut forcement le faire selon le contexte de la requête. Ce qui donne du graphisme généré dynamiquement côté serveur !!!

Voici un exemple où les données côté serveur (on peut imaginer qu'elles viennent d'une base de données à part) sont exploitées pour construire à la volée les graphismes de la page. On découvre avec cet exemple la vraie utilité de SVG...

 

Exemple 6 : graphique des revenus d'une entreprise - généré via PHP de façon dynamique selon les instructions de l'internaute

<?php
$donnees = array( 2011 => array( 23, 45, 87, 42, 81, 99,  6, 55, 31, 10, 80, 66 ),
                  2012 => array( 12, 31, 63, 94, 50, 27, 98, 77, 30,  2, 84, 15 ),
                  2013 => array(  9, 44, 71, 48, 29, 91, 93, 97, 88, 56, 81, 31 ),
                  2014 => array( 61, 33, 40, 81, 97, 98, 55, 29, 19, 62, 68, 12 ),
                  2015 => array( 19, 52, 40, 70, 66, 80, 82, 73,  4,  5,  2, 10 ),
                  2016 => array( 51, 81, 17, 14, 90, 26, 23, 36, 14 ) );

$annee = 2011;
if (isset($_GET) && isset($_GET['annee'])) {
  $annee = intval($_GET['annee']);
}

$graph = 'barres';
if (isset($_GET) && isset($_GET['graph'])) {
  $graph = $_GET['graph'];
}

$d = $donnees[$annee];
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
        <style>
        body { background-color:#dddddd;
               width:960px;
               margin:40px auto;}
        polygon { fill:green; }
        line { stroke:black;
               stroke-width:1; }
        line.graphline { stroke:green;
                         stroke-width:2; }
        text { font-size:20px; }
        </style>
    </head>
    <body>

    <svg width="900" height="200">

    <text x="20" y="110" transform="rotate(270 20,110)">Revenus</text>
    <line x1="40" y1="10" x2="40" y2="120" />
    <line x1="40" y1="120" x2="780" y2="120" />
    <text x="390" y="150"><?php echo $annee; ?></text>

<?php
    $decalage = 60;
    for($i=0; $i<count($d); $i++)
    {
      if ($graph == 'barres' )
      {
        $bottom = 120;
        $top = $bottom - $d[$i];
        $left = $decalage;
        $right = $decalage + 40;
        echo '<polygon points="'
           . $left . ',' . $top . ' '
           . $right . ',' . $top . ' '
           . $right . ',' . $bottom . ' '
           . $left . ',' . $bottom . '" />';
      }
      else /* ligne */
      {
        if ($i > 0)
        {
          $x1 = $decalage - 40;
          $y1 = 120 - $d[$i - 1];
          $x2 = $x1 + 60;
          $y2 = 120 - $d[$i];
          echo '<line class="graphline" '
             . 'x1="' . $x1 . '" '
             . 'y1="' . $y1 . '" '
             . 'x2="' . $x2 . '" '
             . 'y2="' . $y2 . '" />';
        }
      }
      $decalage = $decalage + 60;
    }
?>

    </svg>

    <p>Afficher les revenus pour : 

<?php
    foreach ($donnees as $key => $val) {
      echo '<a href="?annee=' . $key . '&graph=' . $graph . '">' . $key . '</a> ';
    }
?>
    </p>

    <p>Style de graphique :
       <a href="?annee=<?php echo $annee; ?>&graph=ligne">Ligne</a>
       <a href="?annee=<?php echo $annee; ?>&graph=barres">Barres</a>
    </p>

    </body>
</html>

 

 

Vectoriel ≠ Matriciel

Le fait d'être vectoriel est, pour SVG, un point fort du point de vue de qualité visuelle. Une image (ou animation) vectorielle est générée depuis une description mathématique. Elle peut être agrandie sans perte de qualité visuelle.

Une image matricielle est basée sur des pixels. Si on grandit une image matricielle la qualité baisse. Les pixels commencent à se voir à l’œil nu.

 

Exemple 7 : Qualité visuelle des graphisme SVG (remarque : dans cet exemple on voit aussi comment intégrer des hyperliens dans les graphismes SVG)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>SVG</title>
        <style>
        body { font-family:Helvetica, Arial, sans-serif;
          background-image:url(http://www.web-design-codex.fr/wp-content/uploads/2014/10/sample_tilebg.jpg);
          background-repeat:repeat;
          width:960px;
          margin:20px auto; }
        polygon { fill:darkorange;
          stroke:brown;
          stroke-width:20; }
        text { stroke:gold;
          stroke-width:2;
          font-size:40px; }
        img { position:relative;
              top:-10px;}
        </style>
    </head>
    <body>
         <p>L'image SVG est à gauche. L'image PNG est à droite.
            Utilisez la fonction zoom du navigateur pour vérifier
            qu'il n'y pas de perte de qualité visuelle avec
            l'agrandissment de l'image SVG.</p>
         <svg width="400" height="400">
           <a xlink:href="http://www.w3.org/Graphics/SVG/" target="_blank">
             <polygon points="20,20 380,20 380,380 20,380" />
             <text x="120" y="100" transform="rotate(45 120,100)">J&#039;adore SVG</text>
             <text x="100" y="170" transform="rotate(45 100,170)">( cliquez ici )</text>
           </a>
         </svg>
         <a href="http://www.w3.org/Graphics/SVG/" target="_blank">
           <img src="http://www.web-design-codex.fr/wp-content/uploads/2016/09/jadoresvg.png">
         </a>
    </body>
</html>

 

Compatibilité des navigateurs : ATTENTION

Tous les navigateurs ne sont pas encore compatible avec toute la spécification SVG.

Pour les exemples ci-dessous (avec animation), l'utilisation de Firefox ou Chrome est conseillée.

En règle générale, pour tous vos travaux SVG, l'utilisation de Firefox est conseillé car c'est le navigateur le plus complet vis-à-vis cette technologie.

 

SVG et Animation

L'animation est faite en SVG via la balise <animateTransform> : celle-ci est imbriquée dans l'élément qui doit être animé.

 

Exemple 8 : Animation

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>SVG</title>
    <style>
      body { background-color:#555555;
             width:960px;
             margin:20px auto; }
      rect { stroke:black;
             stroke-width:10; }
      rect.orange { fill:darkorange; }
      rect.bleu { fill:skyblue; }
      circle.axe { stroke:black;
             stroke-width:10;
             fill:#aaaaaa; }
      circle.goutte { fill:black; }
    </style>
  </head>
  <body>

    <svg width="800" height="400">

      <rect x="100" y="100" height="200" width="200" class="orange">
        <animateTransform
          attributeName="transform"
          begin="0s"
          dur="4s"
          type="rotate"
          from="0 200 200"
          to="90 200 200"
          repeatCount="indefinite" />
      </rect>
      <circle cx="200" cy="200" r="30" class="axe" />

      <rect x="375" y="100" height="200" width="200" class="bleu">
        <animateTransform
          attributeName="transform"
          begin="0s"
          dur="2s"
          type="rotate"
          from="90 475 200"
          to="0 475 200"
          repeatCount="indefinite" />
      </rect>
      <circle cx="475" cy="200" r="30" class="axe" />

      <circle cx="337" cy="-40" r="20" class="goutte" >
        <animateTransform
          attributeName="transform"
          begin="0s"
          dur="8s"
          type="translate"
          from="0 0"
          to="0 480"
          repeatCount="indefinite" />
      </circle>

      <circle cx="337" cy="-40" r="20" class="goutte" >
        <animateTransform
          attributeName="transform"
          begin="4s"
          dur="8s"
          type="translate"
          from="0 0"
          to="0 480"
          repeatCount="indefinite" />
      </circle>

    </svg>

  </body>
</html>

 

Remarque : dans l'exemple 8 ci-dessus on voit l'utilisation de la balise <rect> au lieu de la balise <polygon> pour faire les rectangles. Les deux existent et selon le besoin l'un est parfois plus pratique que l'autre.

Voir la page (utiliser Firefox ou Chrome) : SVG Animation Démo

 

Intégration des images (jpg, png, etc)

On peut intégrer des images (jpg, png, etc) dans le canevas SVG. Il faut savoir que les images sont matricielles donc ne bénéficieront pas de la conservation de qualité visuelle quand on zoom.

Remarques : dans l'exemple ci-dessous on découvre également l'animation du texte sous deux formes différentes : translation, et apparition lente via manipulation de l'opacité du texte. On découvre aussi l'attribut/valeur fill="freeze" qui conserve l'état final d'un élément à la fin de son animation.

 

Exemple 9 : Incorporer une image dans SVG (avec animation du texte)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>SVG</title>
    <style>
      body { background-color:#555555;
             width:960px;
             margin:20px auto; }
      polygon { fill:darkred; }
      text { font-size:26px;
             fill:darkred; }
      text.invisible { opacity:0; }
    </style>
  </head>
  <body>

    <svg width="800" height="450">

      <image xlink:href="http://www.web-design-codex.fr/wp-content/uploads/2016/09/porsche.jpg" x="0" y="0" height="450px" width="800px"/>

      <text x="800" y="30">Porsche 911 R
        <animateTransform
          attributeName="transform"
          begin="0ms"
          dur="600ms"
          type="translate"
          from="0 0"
          to="-790 0"
          repeatCount="1"
          fill="freeze" />
      </text>

      <polygon points="1010,15 1800,15 1800,25 1020,25" >
        <animateTransform
          attributeName="transform"
          begin="0ms"
          dur="600ms"
          type="translate"
          from="0 0"
          to="-790 0"
          repeatCount="1"
          fill="freeze" />
      </polygon>

      <text x="450" y="80" class="invisible">500 chevaux
        <animate
          attributeName="opacity"
          begin="400ms"
          dur="800ms"
          from="0"
          to="1"
          repeatCount="1"
          fill="freeze" />
      </text>

      <text x="540" y="120" class="invisible">300 km/h...
        <animate
          attributeName="opacity"
          begin="900ms"
          dur="800ms"
          from="0"
          to="1"
          repeatCount="1"
          fill="freeze" />
      </text>

      <text x="630" y="160" class="invisible">193 000 €
        <animate
          attributeName="opacity"
          begin="2600ms"
          dur="800ms"
          from="0"
          to="1"
          repeatCount="1"
          fill="freeze" />
      </text>

    </svg>

  </body>
</html>

 

 

Aller plus loin avec SVG

Le domaine de SVG est vaste. Ci-dessus on n'a vu qu'une minuscule partie. Pour en découvrir plus :

SVG et 3D...

C'est possible si on incorpore du ecmascript (un standard JavaScript) pour transformer un modèle 3D en coordonnées 2D exigées par SVG.

Exemple : Animation d'un cube en 3D par Peter Collingridge [remerciements petercollingridge.co.uk]

 

 

Canvas + JavaScript

Pour faire des dessins à la volée sur une page web, une alternative à SVG est l'utilisation de la balise <canvas> avec du JavaScript.

 

Exemple 10 : Canvas

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Canvas</title>
    <style>
      body { background-color:#dddddd; }
      canvas { background-color:white; }
    </style>
  </head>
  <body>

    <p>Zoomer pour voir si la qualité visuelle est préservée...</p>

    <canvas id="myCanvas" width="475" height="300" />

    <script>
      var c = document.getElementById("myCanvas");
      var ctx = c.getContext("2d");

      ctx.fillStyle = "skyblue";
      ctx.fillRect(30, 30, 190, 190);

      ctx.beginPath();
      ctx.arc(190, 190, 70, 0, 2*Math.PI);
      ctx.fillStyle = "gold";
      ctx.fill();
      ctx.lineWidth = 15;
      ctx.strokeStyle = 'darkslategray';
      ctx.stroke();

      ctx.beginPath();
      ctx.arc(420, 150, 120, 0, 2*Math.PI);
      ctx.lineWidth = 45;
      ctx.strokeStyle = 'darkorange';
      ctx.stroke();

    </script>

  </body>
</html>

 

SVG vs Canvas

SVG - avantages/désavantages :

  • (+) purement vectoriel, SVG est "scalable" (s'adapte à l’échelle) : la qualité de l'image est préservée quand on augmente la résolution (penser par exemple aux fonctionnalités de zoom sur les tablettes et les smartphones)
  • (+) c'est du HTML donc les dessins/animations peuvent être générés facilement par script (PHP par exemple)
  • (+) c'est du HTML donc les éléments dans le graphisme sont manipulables de façon interactive côté client via le DOM (en JavaScript)
  • (+) l'animation des éléments est prévue
  • (-) 3D possible mais seulement en ajoutant JavaScript/ecmascript
  • (-) performance pauvre si beaucoup d'éléments

Canvas - avantages/désavantages :

  • (+) en générale plus rapide que SVG
  • (-) vectoriel pour le programmeur mais le résultat est matriciel : la qualité de l'image n'est pas préservée quand on augmente la résolution
  • (-) c'est procédural (pas comme HTML qui est déclaratif) : il faut coder ! Remarque : on peut générer le code JavaScript avec du PHP mais c'est plus compliqué que générer du HTML.
  • (-) les éléments vectoriels sont perdus à la génération : impossible de manipuler les éléments dans le graphisme de façon interactive côté client via le DOM (en JavaScript)
  • (-) exige un moteur JavaScript
  • (-) pas de fonctionnalité spécifiquement prévue pour l'animation
  • (-) 3D possible mais exige la présence de OpenGL - via getContext('webgl')
  • (-) performance devient pauvre si beaucoup de pixels

La compatibilité avec les différents navigateurs est comparable pour les deux technologies.

 


 

EXERCICES

Pour ces exercices on utilise la balise SVG avec mise en page via CSS (feuille de style interne ou externe).

1. Créer une page web qui affiche le suivant. Pour savoir comment faire, l'exemple n° 4 montre comment mettre plusieurs carrés sur la page, avec différentes couleurs et bordures, et l'exemple n° 7 montre comment afficher du texte et comment y appliquer une rotation. Astuce : pas besoin d'appliquer une rotation sur les rectangles, on l'applique uniquement sur les textes.

svg_exercice1

2. Créer une page web qui montre deux produits ou personnages (images intégrées dans le code SVG) et la popularité de chacun - voir l'exemple ci-dessous. Pour savoir comment faire, les exemples n°4 et n°7 montrent comment afficher des formes et des textes. L'exemple n°9 montre comment intégrer une image dans le SVG.

sondage

3. (PHP) Adapter votre solution pour exercice n° 2 : stocker les chiffres de popularité dans des variables et utiliser un script PHP pour générer la page selon ces chiffres. La modification des chiffres devrait suffire pour modifier les résultats affichés (y compris la largeur de la barre de popularité rouge/bleu, et la positionnement du texte avec le pourcentage, bien sûr !). Testez votre script en modifiant les chiffres dans le code. Voici un bout de code PHP qui montre comment stocker les chiffres :

<?php
$votes_trump = 440;
$votes_clinton = 449;
$votes_total = 1000;
?>

Exemple d'affichage (avec des chiffres Trump 391, Clinton 603, Total 1000)

sondage2

4. (Animation) Améliorer votre solution pour l'exercice n°3 : animez la barre rouge/bleu et faire apparaître le pourcentage à la fin de l'animation de la barre. Comme dans la capture ci-dessous (bien sûr, on garde la possibilité de modifier les chiffres du sondage et ainsi changer les résultats affichés) :

 

sondage.anime

 

5. (Facultatif - pour les avancés) Améliorer votre solution pour l'exercice n°4 : ajouter des boutons de sondage (un bouton par produit/personnage) qui incrémentent les chiffres correspondants (de façon persistante) et qui rafraîchit la page et affiche les nouveaux résultats.

6. Projet individuel / devoir : selon les instructions de l'enseignant.