Etiqueta fuera del arco (gráfico circular) d3.js


Soy nuevo en d3.js y yo estamos tratando de hacer un gráfico circular con él. Solo tengo un problema: no puedo sacar mis etiquetas fuera de mis arcos... Las etiquetas se colocan con arco.centroide

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

¿Quién puede ayudarme con esto?

Author: peller, 2011-11-08

10 answers

Puedo resolver ese problema-con trigonometría:).

Ver violín: http://jsfiddle.net/nrabinowitz/GQDUS/

Básicamente, llamar a arc.centroid(d) devuelve un array [x,y]. Puede usar el Teorema de Pitágoras para calcular la hipotenusa, que es la longitud de la línea desde el centro del pastel hasta el centroide del arco. Luego puede usar los cálculos x/h * desiredLabelRadius y y/h * desiredLabelRadius para calcular el x,y deseado para su anclaje de etiqueta:

.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) +  ")"; 
})

El único inconveniente aquí es que text-anchor: middle ya no es una gran opción - sería mejor configurar el text-anchor basado en el lado del pastel en el que estamos:

.attr("text-anchor", function(d) {
    // are we past the center?
    return (d.endAngle + d.startAngle)/2 > Math.PI ?
        "end" : "start";
})
 58
Author: nrabinowitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-19 23:43:17

Gracias!

Encontré una manera diferente de resolver este problema, pero la tuya parece mejor: -)

Creé un segundo arco con un radio más grande y lo usé para posicionar mis etiquetas.

///// 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) + "%"});
 15
Author: Ibe Vanmeenen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-25 14:43:25

Específicamente para los gráficos circulares, la función d3.layout.pie() formateará los datos con los atributos startAngle y endAngle. El radio puede ser lo que desee (a qué distancia del centro desea colocar la etiqueta).

Combinando estas piezas de información con un par de funciones trigonométricas le permite determinar las coordenadas x e y para las etiquetas.

Considere esto esencia/block .

Con respecto al posicionamiento x/y del texto, la magia es en esta línea (formateado para legibilidad):

.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 nos da nuestro ángulo (theta) en radianes.
  • (radius - 12) es el radio arbitrario que elegí para la posición del texto.
  • -1 * el eje y está invertido (ver más abajo).

Las funciones trigonométricas utilizadas son: cos = adjacent / hypotenuse y sin = opposite / hypotenuse. Pero hay un par de cosas que debemos considerar para que funcionen con nuestras etiquetas.

  1. El ángulo 0 está a las 12 en punto.
  2. El ángulo todavía aumenta en un en el sentido de las agujas del reloj.
  3. El eje y se invierte desde el sistema de coordenadas cartesianas estándar. Positivo y está en la dirección de las 6 en punto hacia abajo.
  4. La x positiva sigue en la dirección de las 3 a la derecha.

Eso arruina las cosas bastante y básicamente tiene el efecto de intercambiar sin y cos. Nuestras funciones trigonométricas se convierten entonces en: sin = adjacent / hypotenuse y cos = opposite / hypotenuse.

Sustituyendo nombres de variables tenemos sin(radians) = x / r y cos(radians) = y / r. Después de alguna manipulación algebraica podemos obtenga ambas funciones en términos de x e y respectivamente r * sin(radians) = x y r * cos(radians) = y. A partir de ahí, solo tienes que conectarlos al atributo transform/translate.

Eso pondrá las etiquetas en la ubicación correcta, para que se vean elegantes, necesita una lógica de estilo como esta:{[19]]}

.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";
    }
  })

Esto hará que las etiquetas de 10:30 en punto a 1:30 en punto y de 4:30 en punto a 7:30 en punto se anclen en el medio (están arriba y abajo), las etiquetas de 1:30 en punto a 4:30 en punto se anclen a la izquierda (están a la derecha), y las etiquetas de 7:30 a 10:30 anclan a la derecha (están a la izquierda).

Las mismas fórmulas se pueden usar para cualquier gráfico radial D3, la única diferencia es cómo se determina el ángulo.

¡Espero que esto ayude a cualquiera que tropiece con él!

 14
Author: clayzermk1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-17 20:10:30

No se si esto ayuda pero pude crear arcos donde coloco texto, tanto en el arco como justo fuera de él. En un caso, donde pongo magnitudes del arco dentro de los arcos, giro el texto en el arco para que coincida con el ángulo del arco. En el otro, donde coloco el texto fuera del arco, es simplemente horizontal. El código se encuentra en: http://bl.ocks.org/2295263

Mi mejor,

Frank

 5
Author: Information Technology,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-19 03:28:04

Sí bebé, es 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)
 2
Author: spencercooly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-30 20:14:09

El siguiente CoffeeScript funcionó para mí para obtener etiquetas todavía dentro de las rebanadas de pastel, pero hacia el borde exterior:

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) + ')'
 1
Author: Sarah Vessels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-29 22:54:35

Esta función calculó el punto central de la porción circular para un gráfico circular. Agrego una función para obtener el punto central del arco. A continuación se muestra la imagen basada en mi nueva función . consulte el enlace: https://github.com/mbostock/d3/issues/1124

 1
Author: Sean Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-07 08:10:48

Esta fue la respuesta de bajo costo con la que estaba contento. Empuja todas las etiquetas horizontalmente (ahí es donde tenía el espacio extra):

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; });
 1
Author: cheepychappy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-18 04:19:17

Así que si quieres ir con una leyenda muy bonita en lugar de texto aleatorio rondando. Encontré una solución bastante buena para las etiquetas. ¿cómo agregar leyenda a un gráfico circular usando D3js? Y cómo centralizar el gráfico circular?

 1
Author: DeadlyChambers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:47

Logré lo mismo dibujando porcentajes como etiquetas fuera del gráfico circular, aquí está el código 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 + '%';
      });
 1
Author: FarazShuja,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-22 06:31:30