Étiquette à l'extérieur de l'arc (graphique circulaire) d3.js
je suis nouveau en d3.js et moi essayons de faire un diagramme avec. J'ai un problème: je ne peux pas obtenir mes étiquettes en dehors de mes arcs... Les étiquettes sont positionnées avec arc.centre de gravité
arcs.append("svg:text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
Qui peut m'aider avec ça?
10 réponses
je peux résoudre ce problème - avec trigonométrie :).
voir violon: http://jsfiddle.net/nrabinowitz/GQDUS/
en gros, appeler arc.centroid(d)
renvoie un tableau [x,y]
. Vous pouvez utiliser le théorème de Pythagore pour calculer l'hypoténuse, qui est la longueur de la ligne du centre de la tarte au centroïde de l'arc. Vous pouvez alors utiliser les calculs x/h * desiredLabelRadius
et y/h * desiredLabelRadius
pour calculer souhaité x,y
pour votre ancrage d'étiquette:
.attr("transform", function(d) {
var c = arc.centroid(d),
x = c[0],
y = c[1],
// pythagorean theorem for hypotenuse
h = Math.sqrt(x*x + y*y);
return "translate(" + (x/h * labelr) + ',' +
(y/h * labelr) + ")";
})
le seul inconvénient ici est que text-anchor: middle
n'est plus un bon choix - vous feriez mieux de mettre le text-anchor
basé sur quel côté du gâteau nous sommes:
.attr("text-anchor", function(d) {
// are we past the center?
return (d.endAngle + d.startAngle)/2 > Math.PI ?
"end" : "start";
})
Merci!
j'ai trouvé une autre façon de résoudre ce problème, mais la vôtre semble meilleure: -)
j'ai créé un second arc avec un plus grand rayon et je l'ai utilisé pour positionner mes étiquettes.
///// Arc Labels /////
// Calculate position
var pos = d3.svg.arc().innerRadius(r + 20).outerRadius(r + 20);
// Place Labels
arcs.append("svg:text")
.attr("transform", function(d) { return "translate(" +
pos.centroid(d) + ")"; })
.attr("dy", 5)
.attr("text-anchor", "middle")
.attr("fill", function(d, i) { return colorL(i); }) //Colorarray Labels
.attr("display", function(d) { return d.value >= 2 ? null : "none"; })
.text(function(d, i) { return d.value.toFixed(0) + "%"});
spécifiquement pour les diagrammes à secteurs, la fonction d3.layout.pie()
formatera les données avec les attributs startAngle
et endAngle
. Le rayon peut être ce que vous désirez (à quelle distance du centre, vous souhaitez placer l'étiquette).
la combinaison de ces éléments d'information avec un couple fonctions trigonométriques vous permet de déterminer les coordonnées x et y pour les étiquettes.
concernant le positionnement x/y du texte, la magie est dans cette ligne (formatée pour la lisibilité):
.attr("transform", function(d) {
return "translate(" +
( (radius - 12) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
", " +
( -1 * (radius - 12) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
")";
})
-
((d.endAngle - d.startAngle) / 2) + d.startAngle
nous donne notre angle (thêta) en radians. -
(radius - 12)
est le rayon arbitraire que j'ai choisi pour la position du texte. -
-1 *
l'axe des y est inversé (voir ci-dessous).
les fonctions de trigo utilisées sont: cos = adjacent / hypotenuse
et sin = opposite / hypotenuse
. Mais il y a certaines choses que nous devons considérer pour que cela fonctionne avec nos étiquettes.
- 0 angle est à 12 heures.
- l'angle augmente encore dans le sens des aiguilles d'une montre.
- l'axe y est inversé par rapport au système de coordonnées cartésien standard. Positif y est dans la direction de 6 heures.
- X positif est toujours dans la direction de 3 heures - droite.
qui gâche les choses un peu et a essentiellement l'effet d'échanger sin
et cos
. Nos fonctions trig deviennent alors: sin = adjacent / hypotenuse
et cos = opposite / hypotenuse
.
substituant des noms de variables nous avons sin(radians) = x / r
et cos(radians) = y / r
. Après quelques manipulations algébriques nous pouvons obtenir les deux fonctions en termes de x et y respectivement r * sin(radians) = x
et r * cos(radians) = y
. À partir de là, il suffit de les brancher dans l'attribut transform/translate.
qui mettra les étiquettes à la bonne place, pour les faire paraître fantaisistes, vous avez besoin d'une certaine logique de style comme celle-ci:
.style("text-anchor", function(d) {
var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
if ( (rads > 7 * Math.PI / 4 && rads < Math.PI / 4) || (rads > 3 * Math.PI / 4 && rads < 5 * Math.PI / 4) ) {
return "middle";
} else if (rads >= Math.PI / 4 && rads <= 3 * Math.PI / 4) {
return "start";
} else if (rads >= 5 * Math.PI / 4 && rads <= 7 * Math.PI / 4) {
return "end";
} else {
return "middle";
}
})
cela fera les étiquettes de 10: 30 heures à 1: 30 heures et de 4: 30 heures à 7:30 heures ancre au milieu (ils sont au-dessus et en dessous), les étiquettes de 1:30 heures à 4:30 heures ancre sur la gauche (ils sont à la droite), et les étiquettes de 7:30 heures à 10:30 heures ancre sur la droite (ils sont à gauche).
les mêmes formules peuvent être utilisées pour n'importe quel graphique radial D3, la seule différence est la façon dont vous déterminez l'angle.
j'espère que cela aidera quiconque trébucher à travers elle!
Je ne sais pas si cela aide, mais j'ai pu créer des arcs où je place du texte, les deux, sur l'arc et juste en dehors. Dans un cas, où je place la grandeur de l'arc dans les arcs, je tourne le texte sur l'arc pour correspondre à l'angle de l'arc. Dans l'autre, où je place le texte en dehors de l'arc, il est simplement horizontal. Le code est situé à: http://bl.ocks.org/2295263
De Mon Mieux
Frank
oui bébé, c'est SOHCAHTOA
function coordinates_on_circle(hyp, angle){
var radian= angle * Math.PI / 180 //trig uses radians
return {
x: Math.cos(radian) * hyp, //adj = cos(r) * hyp
y: Math.sin(radian) * hyp //opp = sin(r) * hyp
}
}
var radius=100
var angle=45
coordinates_on_circle(radius, angle)
le Coffee-script suivant a fonctionné pour moi pour obtenir des étiquettes encore à l'intérieur des tranches de tarte, mais vers le bord extérieur:
attr 'transform', (d) ->
radius = width / 2 # radius of whole pie chart
d.innerRadius = radius * 0.5
d.outerRadius = radius * 1.5
'translate(' + arc.centroid(d) + ')'
cette fonction a calculé le point central de la tranche de tarte pour un graphe à tarte. J'ajoute une fonction pour obtenir le point central de l'arc. Voici une image basée sur ma nouvelle fonction . voir le lien: https://github.com/mbostock/d3/issues/1124
C'était la réponse à faible coût qui me plaisait. Il repousse toutes les étiquettes horizontalement (c'est là que j'ai eu l'espace supplémentaire):
g.append("text")
.attr("transform", function(d) {
var pos = arc.centroid(d);
return "translate(" + (pos[0] + (.5 - (pos[0] < 0)) * radius) + "," + (pos[1]*2) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", function(d) {
return arc.centroid(d)[0] > 0 ? "start" : "end";
})
.text(function(d) { return d.label; });
Donc, si vous voulez aller avec une très jolie légende plutôt que de texte aléatoire traîner. J'ai trouvé une bonne solution pour les étiquettes. comment ajouter une légende à un diagramme à secteurs en utilisant D3js? Et comment centraliser le camembert?
j'ai obtenu le même pourcentage de dessin que les étiquettes à l'extérieur du graphique à secteurs, voici le code http://bl.ocks.org/farazshuja/e2cb52828c080ba85da5458e2304a61f
g.append("text")
.attr("transform", function(d) {
var _d = arc.centroid(d);
_d[0] *= 2.2; //multiply by a constant factor
_d[1] *= 2.2; //multiply by a constant factor
return "translate(" + _d + ")";
})
.attr("dy", ".50em")
.style("text-anchor", "middle")
.text(function(d) {
if(d.data.percentage < 8) {
return '';
}
return d.data.percentage + '%';
});