11 - Dessiner des SVGs


Lien vers le tutoriel original : http://alignedleft.com/tutorials/d3/drawing-svgs


Dessiner des SVGs

Dernière mise à jour le 30 décembre 2012

Maintenant que l’on est familier avec la structure de base d’une image SVG et ses éléments, comment peut-on générer des formes à partir de nos données ?

Vous avez peut-être remarqué que toutes les propriétés des éléments SVG sont spécifiées comme attributs. Ce qui veut dire qu’elles sont inclues comme des paires propriété/valeur, comme ça :

<element property="value"/>

Hum, ça ressemble étrangement à de l’HTML !

<p class="eureka">

On a déjà utilisé les méthodes, bien pratiques, de D3 append() et attr() pour créer de nouveaux éléments HTML et définir leurs attributs. Comme les éléments SVG existent dans le DOM, comme les éléments HTML, on peut utiliser append() et attr() exactement de la même manière pour générer une image SVG !

Créer le SVG

D’abord, on doit créer l’élément SVG dans lequel on placera toutes nos formes.

d3.select("body").append("svg");

Ça trouvera l’élément body et y ajoutera un nouvel élément svg juste avant la balise fermante </body>. Même si ça fonctionnerait, je recommande plutôt :

var svg = d3.select("body").append("svg");

Vous vous rappelez que la plupart des méthodes D3 retournent une référence à l’élément DOM sur lequel elles agissent ? En créant une nouvelle variable svg, on peut garder une trace de la référence transmise par append(). Pensez à svg non comme à une “variable” mais comme à une “référence pointant vers l’objet SVG que l’on vient juste de créer.” Cette référence nous permettra de ne pas répéter notre code plus tard. Plutôt qu’avoir à chercher ce SVG à chaque fois — comme avec d3.select(“svg”) — on dira juste svg.

svg.attr("width", 500)
   .attr("height", 50);

On peut aussi tout écrire en une ligne de code :

var svg = d3.select("body")
            .append("svg")
            .attr("width", 500)
            .attr("height", 50);

Voir la page de démonstration

Inspectez le DOM et voyez qu’il y a, effectivement, un élément SVG vide.

Pour vous simplifier la vie, je vous recommande de stocker les valeurs de largeur et de hauteur dans des variables en haut de votre code, comme ça (voir la source) :

// Largeur et hauteur
var w = 500; //  width == largeur
var h = 50;  // height == hauteur

Je ferai cela pour tous les prochains exemples. En mettant en variables les valeurs de taille, elles peuvent être facilement référencées dans tout notre code, comme suit :

var svg = d3.select("body")
            .append("svg")
            .attr("width", w)   // <-- Ici
            .attr("height", h); // <-- et ici !

Des formes définies par des données

Il est l’heure d’ajouter quelques formes. Retrouvons notre bon vieux ensemble de données

var dataset = [ 5, 10, 15, 20, 25 ];

et utilisons data() pour itérer sur chaque élément de données, en créant un cercle circle pour chacun :

svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle");

Rappelez-vous, selectAll() retournera des références vides pour chacun des cercles circle (qui n’existent pas encore), data() liera nos données aux éléments que l’on s’apprête à créer, enter() retournera une référence placeholder au nouvel élément, et append() ajoutera finalement un cercle circle au DOM.

Pour référencer facilement tous les cercles circle plus tard, créons une nouvelle variable pour stocker toutes ces références :

var circles = svg.selectAll("circle")
                 .data(dataset)
                 .enter()
                 .append("circle");

Super, mais ces cercles ont encore besoin de positions et de tailles. Soyez prévenus : Le code qui suit pourrait vous retourner le cerveau.

circles.attr("cx", function(d, i) {
            return (i * 50) + 25;
        })
       .attr("cy", h/2)
       .attr("r", function(d) {
            return d;
       });

Rangée de cercles de données

Régalez vos yeux de cette démo. Avançons pas à pas dans ce code.

circles.attr("cx", function(d, i) {
            return (i * 50) + 25;
        })

Prend la référence de tous les cercles circle et définit l’attribut cx pour chacun. Nos données ont déjà été liées aux éléments circle, donc pour chaque circle, la valeur de d correspond à la valeur équivalente dans notre ensemble de données (5, 10, 15, 20, ou 25). Une autre valeur, i, est automatiquement définie pour nous. i est une valeur d’index numérique de l’élément courant. En partant de 0, donc pour notre “premier” cercle i == 0, pour le second cercle i == 1 et ainsi de suite. On utilise i pour pousser chaque élément qui suit un peu plus vers la droite, car à chaque itération la valeur de i est incrémentée.

(0 * 50) + 25 retourne 25
(1 * 50) + 25 retourne 75
(2 * 50) + 25 retourne 125
(3 * 50) + 25 retourne 175
(4 * 50) + 25 retourne 225

Pour être sûr que i est disponible dans votre fonction, vous devez l’inclure en argument dans la définition de votre fonction (function(d, i)). Vous devez aussi inclure d, même si vous ne comptez pas l’utiliser dans votre fonction (comme c’est le cas ci-dessus).

Ligne suivante.

.attr("cy", h/2)

h est la hauteur de notre SVG en entier, donc h/2 est la moitié de sa hauteur. Ça a pour effet d’aligner tous les cercles circle de manière verticale.

.attr("r", function(d) {
    return d;
});

Enfin, le rayon r de chaque cercle est défini simplement à d, la valeur correspondante.

Oh, les jolies couleurs !

Les couleurs de remplissage et de contour sont d’autres attributs que vous pouvez définir en utilisant les mêmes méthodes. En ajoutant juste ce code

.attr("fill", "yellow")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
    return d/2;
});

vous pouvez obtenir (ce résultat.):

Cercles de données colorés

Bien sûr, vous pouvez écrire des fonctions pour faire correspondre n’importe quelle combinaison propriété/attribut. Le truc avec la visualisation de données est de bien choisir les cartographies (mappings), pour que l’expression visuelle de vos données soit compréhensible et utile à celui qui la regarde.