Il est possible d'ajouter du texte dans un diagramme camembert

À faire vous même 11.1

script.js


var tab=[15,30,35,70];
var couleurs=["green","black","purple","blue"];
var body=d3.select("body");
var svg=body.append("svg");
svg.attr({"width":"400px","height":"400px"})
svg.style("border","1px solid black");

var pieTab=d3.layout.pie();
pieTab.value(function(d){
		return d;
	});

var arc=d3.svg.arc();
arc.outerRadius(180);

var grp=svg.append("g").attr("transform","translate(200,200)");
var graph=grp.selectAll("path").data(pieTab(tab))
graph.enter()
	.append("path")
	.attr("fill",function(d,i){
			return(couleurs[i]);
		})
	.attr("d",arc);
var texte=grp.selectAll("text").data(pieTab(tab));
texte.enter()
	.append("text")
	.attr("transform", function(d) {
		d.innerRadius=0;
		d.outerRadius=180;
        return "translate(" + arc.centroid(d) + ")";
    })
    .attr("text-anchor", "middle")
	.attr("fill","white")
    .text(function(d) {
        return d.data;
    });
        

Testez ce code


Quelques commentaires sur le code du "À faire vous même 11.1" :

La seule nouveauté, par rapport aux exemples précédents, est que nous ajoutons un text au groupe grp :


var texte=grp.selectAll("text").data(pieTab(tab));
texte.enter()
	.append("text")
	.attr("transform", function(d) {
		d.innerRadius=0;
		d.outerRadius=180;
        return "translate(" + arc.centroid(d) + ")";
    })
    .attr("text-anchor", "middle")
	.attr("fill","white")
    .text(function(d) {
        return d.data;
    });
        

La transformation


.attr("transform", function(d) {
    d.innerRadius=0;
    d.outerRadius=180;
    return "translate(" + arc.centroid(d) + ")";
})
        

nous permet d'afficher le texte correctement. Sans cette transformation, tous les textes seraient affichés au centre du camembert. Pour que cela fonctionne correctement, il est nécessaire de renseigner les "innerRadius" et "outerRadius".

.attr("text-anchor", "middle") permet de bien centrer le texte, alors que .attr("fill","white") permet d'avoir un texte en blanc.

.text(function(d) {return d.data;}); permet d'afficher le texte (qui correspond aux valeurs contenues dans le tableau tab). J'attire votre attention sur le d.data, pourquoi ce "data" ?

Il ne faut pas perdre de vue que le layout "pie" a transformé nos données afin de les rendre compatibles avec la construction d'un diagramme camembert. Voici à quoi ressemblent nos données après transformation :


Object { data: 15, value: 15, startAngle: 5.654866776461628, endAngle: 6.283185307179586, padAngle: 0, innerRadius: 0, outerRadius: 180 }
Object { data: 30, value: 30, startAngle: 4.39822971502571, endAngle: 5.654866776461628, padAngle: 0, innerRadius: 0, outerRadius: 180 }
Object { data: 35, value: 35, startAngle: 2.9321531433504733, endAngle: 4.39822971502571, padAngle: 0, innerRadius: 0, outerRadius: 180 }
Object { data: 70, value: 70, startAngle: 0, endAngle: 2.9321531433504733, padAngle: 0, innerRadius: 0, outerRadius: 180 }
        

Nous avons des objets JavaScript relativement complexes, la seule chose à retenir que les valeurs de notre tableau se trouvent dans l'attribut data des différents objets. Donc, pour récupérer les valeurs du tableau, il nous faudra écrire d.data


Il est possible d'utiliser des données plus complexes, par exemple, un tableau d'objets JavaScript :


var tab=[{"valeur": 15, "nom":"A"},{"valeur": 30, "nom":"B"},{"valeur": 35, "nom":"C"},{"valeur": 70, "nom":"D"}];
        

Chaque objet comporte 2 attributs : "valeur" et "nom". tab[1].valeur est égal à 30 et tab[2].nom est égal "C".

À faire vous même 11.2

Que vaut tab[0].nom ? et tab[3].valeur ?


À faire vous même 11.3

Compléter le code ci-dessous afin d'obtenir ceci :


var tab=[{"valeur": 15, "nom":"A"},{"valeur": 30, "nom":"B"},{"valeur": 35, "nom":"C"},{"valeur": 70, "nom":"D"}];
var couleurs=["green","black","purple","blue"];
var body=d3.select("body");
var svg=body.append("svg");
svg.attr({"width":"400px","height":"400px"})
svg.style("border","1px solid black");

var pieTab=d3.layout.pie();
pieTab.value(function(d){
		return d.valeur;
	});

var arc=d3.svg.arc();
arc.outerRadius(180);

var grp=svg.append("g").attr("transform","translate(200,200)");
var graph=grp.selectAll("path").data(pieTab(tab))
graph.enter()
	.append("path")
	.attr("fill",function(d,i){
			return(couleurs[i]);
		})
	.attr("d",arc);
............
............
............
............
        

Il est possible de réorganiser le code, au lieu de lier les données à la fois aux chemins (path) et aux textes (text), il est possible de lier les données directement aux groupes qui contiendront un chemin et un texte. Pour l'instant, nous avons un groupe (grp), qui contient plusieurs chemins et plusieurs textes. Dans la version que nous allons développer ci-dessous, nous relierons les données aux groupes, nous aurons alors plusieurs groupes (autant de groupes qu'il y a de données dans le tableau), chaque groupe contiendra un chemin (path) et un texte.

À faire vous même 11.4

script.js


var tab=[{"valeur": 15, "nom":"A"},{"valeur": 30, "nom":"B"},{"valeur": 35, "nom":"C"},{"valeur": 70, "nom":"D"}];
var couleurs=["green","black","purple","blue"];
var body=d3.select("body");
var svg=body.append("svg");
svg.attr({"width":"400px","height":"400px"})
svg.style("border","1px solid black");

var pieTab=d3.layout.pie();
pieTab.value(function(d){
		return d.valeur;
	});

var arc=d3.svg.arc();
arc.outerRadius(180);

var grp=svg.selectAll("g").data(pieTab(tab))
grp.enter()
    .append("g")
    .attr("transform","translate(200,200)");

grp.append("path")
	.attr("fill",function(d,i){
			return(couleurs[i]);
		})
	.attr("d",arc);

grp.append("text")
	.attr("transform", function(d,i) {
		d.innerRadius=0;
		d.outerRadius=180;
        return "translate(" + arc.centroid(d) + ")";
    })
    .attr("text-anchor", "middle")
	.attr("fill","white")
    .text(function(d,i) {
        return d.data.nom;
    });
        

Dans le code ci-dessus, comme indiqué plus haut, nous associons les données à des groupes svg (un groupe différent pour chaque donnée). A chacun des groupes nous ajoutons un chemin et un texte.


.text(function(d,i) {
    return d.data.nom;
});
        

Dans le code ci-dessus, le paramètre d correspond à une des données présentes dans le tableau tab (parce que le tableau tab est lié aux groupes (grp) et que le texte text se trouve dans un groupe).

À faire vous même 11.5

À partir des données suivantes (PIB des pays en 2014) :


[{"valeur": 18287000, "nom":"États-Unis"},{"valeur": 11285000, "nom":"Chine"},{"valeur": 4882000, "nom":"Japon"},{"valeur": 3909000, "nom":"Allemagne"},{"valeur": 3003000, "nom":"Royaume-Uni"},{"valeur":2935000, "nom":"France"}];
        

Créez un programme permettant d'obtenir ceci :


Il est possible de créer une légende :

À faire vous même 11.6

Étudiez attentivement ce programme après l'avoir testé


var tab=[{"valeur": 18287000, "nom":"États-Unis"},{"valeur": 11285000, "nom":"Chine"},{"valeur": 4882000, "nom":"Japon"},{"valeur": 3909000, "nom":"Allemagne"},{"valeur": 3003000, "nom":"Royaume-Uni"},{"valeur":2935000, "nom":"France"}];
var couleurs=["green","black","purple","blue","grey","olive"];
var body=d3.select("body");
var svg=body.append("svg");
svg.attr({"width":"600px","height":"600px"})

var pieTab=d3.layout.pie();
pieTab.value(function(d){
		return d.valeur;
	});

var arc=d3.svg.arc();
arc.outerRadius(200);

var grp=svg.selectAll("g.arcs").data(pieTab(tab))
grp.enter()
    .append("g")
    .attr("class","arcs")
    .attr("transform","translate(210,350)");

grp.append("path")
	.attr("fill",function(d,i){
			return(couleurs[i]);
		})
	.attr("d",arc);

var leg=svg.selectAll("g.legende").data(pieTab(tab))
leg.enter()
    .append("g")
    .attr("class","legende")
    .attr("transform",function(d,i){
        return "translate(450,"+(100+30*i)+")";
        });

leg.append("rect")
	.attr("width",15)
	.attr("height",15)
	.attr("fill",function (d,i){
		return couleurs[i];
	});
leg.append("text")
	.attr("x", 25)
	.attr('y', 12)
	.attr("fill","black")
	.style("font-size","12px")
    .text(function(d,i) {
        return d.data.nom;
    });
        


var leg=svg.selectAll("g.legende").data(pieTab(tab))
leg.enter()
    .append("g")
    .attr("class","legende")
    .attr("transform",function(d,i){
        return "translate(450,"+(100+30*i)+")";
        });
        

Comme vous pouvez le constater, nous créons une série de groupe (leg) qui sera associée aux données contenues dans tab. Afin de ne pas "confondre" avec les groupes qui ont été utilisés pour créer le diagramme (grp), nous avons attribué une classe différente à chacune des séries de groupes (la classe arc pour les groupes associés au diagramme et la classe legende pour les groupes associés à la légende).

J'insiste encore sur le fait qu'à chaque ligne de la légende correspond un nouveau groupe. Il y aura autant de groupes avec la classe legende qu'il y a de données dans le tableau tab.


leg.append("rect")
	.attr("width",15)
	.attr("height",15)
	.attr("fill",function (d,i){
		return couleurs[i];
	});
leg.append("text")
	.attr("x", 25)
	.attr('y', 12)
	.attr("fill","black")
	.style("font-size","12px")
    .text(function(d,i) {
        return d.data.nom;
    });
        

À chaque groupe de classe legende on ajoute un rectangle et un texte. Attention les coordonnées du texte sont données par rapport au coin haut-gauche du groupe (même chose pour les rectangles).

Cet exemple est un peu difficile, n'hésitez pas à poser des questions.

À faire vous même 11.7

Ajoutez un titre afin d'obtenir ceci :


Il est possible de réaliser un diagramme camembert dynamique :

À faire vous même 11.8

script.js


var tab_0=[30,150,27,34];
var tab_1=[25,120,40,75];
var tab_2=[40,110,80,76];
var tab=[tab_0,tab_1,tab_2]
var n=0;
var couleurs=["green","yellow","purple","blue"];
var body=d3.select("body");
var svg=body.append("svg");
svg.attr({"width":"400px","height":"400px"})
svg.style("border","1px solid black");

var pieTab=d3.layout.pie();
pieTab.value(function(d){
        return d;
    });

var arc=d3.svg.arc();
arc.outerRadius(180);

var grp=svg.append("g").attr("transform","translate(200,200)");
var graph=grp.selectAll("path").data(pieTab(tab_0))
graph.enter()
	.append("path")
	.attr("fill",function(d,i){
			return(couleurs[i]);
		})
	.attr("d",arc)
	.each(function(d){this._current=d;});

function update(data){
    graph.data(pieTab(data));
    graph.transition().duration(750).attrTween("d", arcTween);

}

function arcTween(a) {
  var i = d3.interpolate(this._current, a);
  this._current = i(0);
  return function(t) {
    return arc(i(t));
  };
}
setInterval(function() {
	if (n==2){
		n=-1;
	}
	n=n+1;
	update(tab[n]);
}, 3000);
        

Testez ce code


Même si la structure reste quelque peu identique à ce nous avons vu dans l'activité 9 (présence d'une fonction update), il y a tout de même beaucoup de différence. Je ne vais pas entrer dans les détails car cela est un peu complexe. Si vous avez besoin de construire un diagrame camembert dynamique, il suffira de reprendre la structure exposé ici. Quelques points à retenir :