Graphe Radar en HTML5

Il m'est arrivé récemment de me plonger dans l'univers mirifique et passionnant (Et encore j'en oublie ;) ) de HTML5.
HTML5 est une vraie avancée par rapport à HTML ; pas une révolution, car on conserve globalement le fonctionnement du HTML tel qu'on le connait (ce qui est un soulagement pour tous...), mais une avancée car il apporte un certain nombre d'objets très intéressants.
C'est le cas de la nouvelle balise
, qui permet de faire en HTML des choses comme ça :




Cette balise permet de réaliser de nombreuses opérations graphiques, autrefois très compliquées (voire impossibles) à faire. Notamment :

  • le tracé de ligne
  • le tracé de formes vides
  • le tracé de formes pleines
  • le tracé de courbes de bézier

...etc...

Ces fonctions sont notamment particulièrement indiquées pour réaliser des graphes dans des pages HTML.

Je vous propose, dans le petit exemple suivant, le code permettant d'afficher un graphe de type radar.
Pour utiliser ce code, copier le et coller dans un fichier CanvasGraph.htm sur votre disque dur.
La syntaxe d'appel sera :

CanvasGraph.htm?nb=8&vmin=0&vmax=10&k0=test0&v0=10&k1=test1&v1=3&k2=test2&v2=9&k3=test3&v3=8&k4=test4&v4=7&k5=test5&v5=3&k6=test6&v6=2&k7=test7&v7=8

Il y a quelques indications dans le code au sein des fonctions, n'hésitez pas à laisser des commentaires si vous voulez éclaircir certains points.
Ce qu'il faut retenir :

  • Il faut créer une balise de type canvas
  • En javascript, récupérer le lien vers l'objet Canvas et vers le Context 2D
  • Pour afficher : on commence par
    context.beginPath()
  • Puis les requêtes de dessin :
    context.moveTo();
  • Puis
    context.closePath();
  • Puis
    context.stroke();


Le code :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Untitled Page</title>
</head>
<body>
<canvas id="canvasElem" width="400" height="400">

Texte si le navigateur ne supporte pas le HTML Canvas

</canvas>

<script language="javascript">

    // Affichage du graphe de type radar
    //
    // Usage : CanvasGraph.htm?nb=8&vmin=0&vmax=10&k0=test0&v0=10&k1=test1&v1=3&k2=test2&v2=9&k3=test3&v3=8&k4=test4&v4=7&k5=test5&v5=3&k6=test6&v6=2&k7=test7&v7=8
    // avec :
    //      nb : nb de points dans le graphe radar
    //      vmin : la valeur du cercle le plus petit
    //      vmax : la valeur du cercle le plus grand
    //      k0 : le texte pour la première valeur
    //      v0 : la première valeur
    //      k1 : le texte pour la deuxième valeur
    //      v1 : la deuxième valeur
    //      ...
    //      k(nb-1) : le texte de la denière valeur
    //      v(nb-1) : la dernière valeur

    // Les constantes d'affichage
    var centerX = 200;      // L'abscisse du centre du graphe
    var centerY = 200;      // L'ordonnée du centre du graphe
    var radiusMax = 100;    // Le rayon extérieur du graphe

    var flag_isok = true;   // Un falg permettant de vérifier que toutes les valeurs en entrée sont ok

    // Lecture des valeurs en entrée
    var nb = parseInt(getParameterByName('nb'));

    // Lecture de la vmin et vmax
    var vmin = parseInt(getParameterByName('vmin'));
    var vmax = parseInt(getParameterByName('vmax'));

    // On teste les variables en entrée
    if (isNaN(nb) || isNaN(vmin) || isNaN(vmax)) {
        flag_isok = false;
    }

    // On crée le tableau
    var k = new Array();
    var v = new Array();

    if (flag_isok) {
        k.length = nb;
        v.length = nb;
        // Lecture des paramètres de la querystring
        for (i = 0; i < nb; i++) {
            v[i] = getParameterByName("v" + i);
            k[i] = getParameterByName("k" + i);

            if (isNaN(v[i])) 
                flag_isok = false;
        }
    }

    var elem;
    var context;

    // On récupère l'objet canvas
    elem = document.getElementById('canvasElem');
    if (!elem || !elem.getContext) {
        // Problème grave
        throw "Problème de récupération du canvaselem";
    }

    // On récupère le contexte 2D
    context = elem.getContext('2d');
    if (!context) {
        throw "Problème de récupération du contexte 2D";
    }

    // Le navigateur est compatible, le contexte a bien été récupéré, on peut continuer...

    function getParameterByName(name)
    {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        var regexS = "[\\?&]" + name + "=([^&#]*)";
        var regex = new RegExp(regexS);
        var results = regex.exec(window.location.href);
        if(results == null)
        return "";
        else
        return decodeURIComponent(results[1].replace(/\+/g, " "));
    }

    function DrawChart() {
        if (context) {
            // On affiche les cercles
            for (i=vmin ; i<=vmax; i++) {
                context.strokeStyle = "#000000";
               context.beginPath();
                context.arc(centerX, centerY, i/vmax*radiusMax, 0, Math.PI * 2, true);
                context.closePath();
                context.stroke();
            }

            // On affiche la grille (la croix)
            context.beginPath();
            context.lineWidth = 0.5;
            context.moveTo(centerX - radiusMax - 10, centerY);
            context.lineTo(centerX + radiusMax + 10, centerY);
            context.moveTo(centerX , centerY - radiusMax - 10);
            context.lineTo(centerX , centerY + radiusMax + 10);
            context.closePath();
            context.stroke();

            // On dessine le polygone représentant les valeurs des points
            context.beginPath();
            context.strokeStyle = "#000055";
            context.fillStyle = "#0000FF";  // Ici, le polygone est plein
            context.globalAlpha = 0.8;  // Légèrement transparent, c'est plus joli
            var currentAngle = -Math.PI/2;
            context.moveTo(centerX + Math.cos(currentAngle) * v[0] / vmax * radiusMax, centerY + Math.sin(currentAngle) * v[0] / vmax * radiusMax);
            for (i = 1; i < nb; i++) {
                currentAngle = currentAngle + 2 * Math.PI / nb;
                // On se place au bon endroit, sur le bon cercle...
                context.lineTo(centerX + Math.cos(currentAngle) * v[i] / vmax * radiusMax, centerY + Math.sin(currentAngle) * v[i] / vmax * radiusMax);
            }
            context.closePath();
            context.stroke();
            context.fill();
            context.globalAlpha = 1.0;

            // On met les bons textes
            context.beginPath();
            context.fillStyle = "#000000";
            context.font = "12px sans-serif";
            context.textAlign = "center";
            context.textBaseline = "middle";
            for (i = 0; i < nb; i++) {
                currentAngle = -Math.PI / 2 + i*(2 * Math.PI / nb);
                // On se place au bon endroit
                context.fillText(k[i], centerX + Math.cos(currentAngle) * (radiusMax + 20), centerY + Math.sin(currentAngle) * (radiusMax + 20));
            }
            context.closePath();
            context.stroke();

        }
    }



    // Dessin
    if (flag_isok)
        DrawChart();
    else
        alert('Une des variables en entrée n\'est pas un entier');

</script>
</body>
</html>


HTML5 ouvre de nombreuses perspectives pour manipuler des formes et réaliser des dessins.
A titre d'exemple, nous utilisons du HTML5 chez Nexemble pour réaliser un éditeur de niveaux de jeux vidéo. Si vous êtes sages, vous aurez bientôt des photos... ;)
Previous
Next Post »