Dans D3.js, D3 est l'écronyme de Data-Driven Document. Cela signifie que des graphiques peuvent être créés à partir des données. Ce concept est la clé de D3.js, la principale fonctionnalité étant le data binding, traduisez, données liées our liaison de données.
Prenons une simple illustration : supposons que vous ayez un ensemble de données à afficher dans un graphique à barres. Vous pouvez créer une boucle pour parcourir vos données et afficher chaque barre. D3.js offre une meilleure option: le data binding. Avec cette fonctionnalité, vous pouvez facilement et simplement associer votre ensemble de données à votre graphique.
Commençons par cet exemple très simple. Source : (Scrimba):
// Set of data
var dataset = ['A', 'B', 'C', 'D', 'E'];
// For each data from dataset, create a new section
d3.select('body')
.selectAll('p')
.data(dataset)
.enter()
.append('p')
.text('Paragraph');
Vous pouvez constater que l'exemple ci-dessus affiche - sans boucle - 5 paragraphes
Ce qui peut paraître étrange est que la sélection est réalisée avant
l'ajout des paragraphes. selectAll('p') est appelé avant append('p').
Détaillons le code ci-dessus.
Si vous ne comprenez pas cette section, pas d'inquiétudes ! Acceptez simplement l'idée que D3.js va créer autant de nouveaux éléments qu'il y a de cellules dans le tableau.
La première ligne spécifie le corps de la page comme parent (pour y ajouter les paragraphes plus tard).
Ensuite, on sélectionne tous les éléments existants de type <p>. Comme il n'y
en a pas, `selecAll('p') retourne une sélection vide. Voici l'objet retourné :
_groups: [NodeList(0)]
_parents: [body]
__proto__: Object
Lorque l'on appelle ensuite data(dataset), la sélection précédente est liée avec les
5 éléments du tableau. data(dataset) retoune 5 sélection (toujours vides) :
_groups: Array(1)
0: (5) [empty × 5]
length: 1
__proto__: Array(0)
_parents: [body]
_enter: [Array(5)]
_exit: [Array(0)]
__proto__: Object
enter() identifie les élements qui auront besoin d'être ajoutés lorsque le tableau
est plus grand que la sélection. C'est le cas ici, puisque chaque sélection est vide.
_groups: Array(1)
0: (5) [rt, rt, rt, rt, rt]
length: 1
__proto__: Array(0)
_parents: [body]
__proto__: Object
Lors de l'appel de la méthode append('p'), l'élement <p> est ajouté dans les
5 éléments créés précédemment :
_groups: Array(1)
0: (5) [p, p, p, p, p]
length: 1
__proto__: Array(0)
_parents: [body]
__proto__: Object
Vous pouvez constater que les 5 éléments <p> sont créés dans la page.
Si ce n'est toujours pas clair, vous pouvez consultez cette page qui détaille le concept avec la notion de jointures : Thinking with Joins.
Cinq nouveaux éléments sont créés, mais notre jeu de données n'est pas lié à nos éléments.
Heureusement, la fonction .text() peut être appelée avec une fonction anomymous
en paramètre. Voici ci-dessous la syntaxe pour lier notre ensemble de données à nos balises <p>.
// Set of data
var dataset = ['A', 'B', 'C', 'D', 'E'];
// For each data from dataset, create a new section
d3.select('body')
.selectAll('p')
.data(dataset)
.enter()
.append('p')
.text(function(id) { return 'Section ' + id; });
Voila comment nos données sont liées avec les nouveaux éléments:
Une dernière remarque importante. La liaison n'existe qu'au momment de l'appel des fonctions data(dataset).
N'imaginez pas que les graphiques se mettront automatiquement à jour lorsque les données changeront.
Il faudra à nouveau associer les données avec la fonction update() cette fois-ci.
Les fonctions anonymes peuvent être écrire sous al forme de fonctions fléchées (arrow function). Cette syntaxe :
.text(function(id) { return 'Section ' + id; });
est équivalente à:
.text((id) => 'Section ' + id; );
Dans la suite, j'utiliserai cette syntaxe.
Plus vous pratiquerez, plus vous comprendrez que ce mécanisme est bien plus pratique qu'une boucle qui parcourt les jeux de données.