Étiquette à l'extérieur de l'arc (tableau à tranches) d3.js

Je suis nouveau sur d3.js et j'essaie de créer un diagramme Pie. Je n'ai qu'un seul problème: je ne peux pas obtenir mes étiquettes à l'extérieur de mes arcs … Les étiquettes sont positionnées avec arc.centroid

arcs.append("svg:text") .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) .attr("text-anchor", "middle") 

Qui peut m'aider avec ça?

Je peux résoudre ce problème – avec la trigonométrie :).

Voir violon: http://jsfiddle.net/nrabinowitz/GQDUS/

Fondamentalement, 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 centre de l'arc. Ensuite, vous pouvez utiliser les calculs x/h * desiredLabelRadius et y/h * desiredLabelRadius pour calculer le x,y désiré x,y pour votre ancre 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 l' text-anchor: middle n'est plus un excellent choix – vous préfériez le réglage de l' text-anchor du text-anchor fonction de quel côté de la tarte nous sommes sur:

 .attr("text-anchor", function(d) { // are we past the center? return (d.endAngle + d.startAngle)/2 > Math.PI ? "end" : "start"; }) 

Merci!

J'ai trouvé un moyen différent de résoudre ce problème, mais le vôtre semble mieux 🙂

J'ai créé un deuxième arc avec un rayon plus grand et 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 circulaires, la fonction d3.layout.pie() formatera les données avec des 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 informations avec quelques fonctions trigonométriques vous permet de déterminer les coordonnées x et y pour les étiquettes.

Considérez ce gist / block .

En ce qui concerne 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 (theta) en radians.
  • (radius - 12) est le rayon arbitraire que j'ai choisi pour la position du texte.
  • -1 * l'axe y est inversé (voir ci-dessous).

Les fonctions trigonométriques utilisées sont: cos = adjacent / hypotenuse et sin = opposite / hypotenuse . Mais il y a quelques choses que nous devons considérer pour que celles-ci fonctionnent avec nos étiquettes.

  1. 0 angle est à 12 heures.
  2. L'angle augmente toujours dans le sens des aiguilles d'une montre.
  3. L'axe y est inversé à partir du système de coordonnées cartésien standard. Positif y est en direction de 6 heures en bas.
  4. Positif x est toujours dans la direction de 3 heures – à droite.

Cela gâche un peu les choses et a essentiellement pour effet d'échanger des sin et des cos . Nos fonctions trigonomiques deviennent alors: sin = adjacent / hypotenuse et cos = opposite / hypotenuse .

En remplaçant les noms de variables, nous avons le sin(radians) = x / r et cos(radians) = y / r . Après une certaine manipulation algébrique, nous pouvons obtenir les deux fonctions en termes de x et y respectivement r * sin(radians) = x et r * cos(radians) = y . De là, il suffit de les connecter à l'attribut transform / translate.

Cela mettra les étiquettes au bon endroit, afin de les rendre fantastiques, vous avez besoin d'une logique de style comme ceci:

 .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 rendra les étiquettes de 10h30 à 1h30 et de 4h30 à 7h30 au point d'ancrage (elles sont au-dessus et au-dessous), les étiquettes de 1 : 30 heures à 4:30 heures d'ancrage à gauche (elles sont à droite) et les étiquettes de 7h30 à 10h30 à l'ancre à droite (elles sont à la la gauche).

Les mêmes formules peuvent être utilisées pour tout diagramme radial D3, la seule différence consiste à déterminer l'angle.

J'espère que cela aidera tout le monde à se heurter!

Je ne sais pas si cela aide, mais j'ai pu créer des arcs où je place le texte, les deux, sur l'arc et juste à l'extérieur. Dans un cas, où je place des grandeurs de l'arc dans les arcs, je tourne le texte sur l'arc pour qu'il corresponde à l'angle de l'arc. Dans l'autre, où je place le texte en dehors de l'arc, il est tout simplement horizontal. Le code se trouve à l' adresse suivante : http://bl.ocks.org/2295263

De mon mieux,

Franc

Le CopyScript suivant a fonctionné pour moi pour obtenir des étiquettes encore dans les 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 graphique de tarte. J'ajoute une fonction pour obtenir le point central de l'arc. Voici une image basée sur ma nouvelle fonction. Reportez-vous au lien: https://github.com/mbostock/d3/issues/1124

C'était la réponse peu coûteuse avec laquelle j'étais content. Il pousse toutes les étiquettes horizontalement (c'est là que j'avais 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 belle légende à la recherche de texte au hasard au hasard. J'ai trouvé une très bonne solution aux étiquettes. Comment ajouter une légende à un diagramme circulaire à l'aide de D3js? Et comment centraliser le graphique circulaire?

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) 

J'ai obtenu le même pourcentage en exprimant le pourcentage en tant qu'étiquettes en dehors du diagramme à 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 + '%'; });