una porcentajes los hacer hacen graficos grafico grafica dona construye como anillo javascript html svg d3.js

javascript - porcentajes - grafico anillo tableau



D3 ponga etiquetas de arco en un gráfico circular si hay suficiente espacio (2)

Esta pregunta se ha hecho varias veces antes.

Las soluciones que he sugerido para rotate la etiqueta, pero nunca me han satisfecho del todo. Parte de esto fue la horrible representación de la fuente hecha por algunos buscadores y la pérdida de legibilidad que trae consigo y el extraño flip cuando una etiqueta cruza la línea de 180° . En algunos casos, los resultados fueron aceptables e inevitables, por ejemplo, cuando las etiquetas eran demasiado largas.

Una de las otras soluciones, la sugerida por Lars, es colocar las etiquetas fuera del gráfico circular. Sin embargo, eso simplemente empuja las etiquetas hacia afuera, otorgándoles un radio mayor, pero no resuelve completamente el problema de overlap .

La otra solución es usar la técnica que sugieres: simplemente elimina las etiquetas que no encajan.

Ocultar etiquetas desbordadas

Compare Original , que tiene una etiqueta >= 65 desbordando a Solución donde la etiqueta de desbordamiento se ha ido.

Reduciendo el problema

La idea clave es ver que este problema es encontrar si un polígono convexo ( un rectángulo , el cuadro delimitador) está contenido dentro de otro polígono convexo ( -ish ) ( una cuña ).

El problema puede reducirse a encontrar si todos los puntos del rectángulo se encuentran dentro de la cuña o no. Si lo hacen, entonces el rectángulo se encuentra dentro del arco.

¿Un punto se encuentra dentro de una cuña

Ahora esa parte es fácil. Todo lo que uno tiene que hacer es verificar:

  1. La distancia del punto desde el centro es menor que el radius
  2. El ángulo subtendido por el punto en el centro está entre el startAngle y el startAngle endAngle del arco.

function pointIsInArc(pt, ptData, d3Arc) { // Center of the arc is assumed to be 0,0 // (pt.x, pt.y) are assumed to be relative to the center var r1 = d3Arc.innerRadius()(ptData), // Note: Using the innerRadius r2 = d3Arc.outerRadius()(ptData), theta1 = d3Arc.startAngle()(ptData), theta2 = d3Arc.endAngle()(ptData); var dist = pt.x * pt.x + pt.y * pt.y, angle = Math.atan2(pt.x, -pt.y); // Note: different coordinate system. angle = (angle < 0) ? (angle + Math.PI * 2) : angle; return (r1 * r1 <= dist) && (dist <= r2 * r2) && (theta1 <= angle) && (angle <= theta2); }

Encuentra el cuadro delimitador de las etiquetas

Ahora que tenemos eso fuera del camino, la segunda parte es descubrir cuáles son las cuatro esquinas del rectángulo. Eso, también, es fácil:

g.append("text") .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) .attr("dy", ".35em") .style("text-anchor", "middle") .text(function(d) { return d.data.age; }) .each(function (d) { var bb = this.getBBox(), center = arc.centroid(d); var topLeft = { x : center[0] + bb.x, y : center[1] + bb.y }; var topRight = { x : topLeft.x + bb.width, y : topLeft.y }; var bottomLeft = { x : topLeft.x, y : topLeft.y + bb.height }; var bottomRight = { x : topLeft.x + bb.width, y : topLeft.y + bb.height }; d.visible = pointIsInArc(topLeft, d, arc) && pointIsInArc(topRight, d, arc) && pointIsInArc(bottomLeft, d, arc) && pointIsInArc(bottomRight, d, arc); }) .style(''display'', function (d) { return d.visible ? null : "none"; });

La médula de la solución está en each función. Primero colocamos el texto en el lugar correcto para que DOM lo represente. Luego usamos el método getBBox() para obtener el cuadro delimitador del text en el espacio del usuario . Un nuevo espacio de usuario es creado por cualquier elemento que tenga un atributo de transform establecido en él . Ese elemento, en nuestro caso, es el cuadro de text sí. Entonces, el recuadro delimitador devuelto es relativo al centro del texto, ya que hemos establecido que el text-anchor sea ​​el middle .

La posición del text relativa al arc se puede calcular ya que hemos aplicado la transformación ''translate('' + arc.centroid(d) + '')'' . Una vez que tenemos el centro, calculamos los topLeft , topRight , bottomLeft y bottomRight y vemos si todos se encuentran dentro de la wedge .

Finalmente, determinamos si todos los puntos se encuentran dentro de la cuña y si no encajan, establezca la propiedad de CSS de la display en none .

Demostración de trabajo

Original

Solución

Nota

  1. Estoy utilizando el innerRadius que, si no es cero, hace que la wedge no sea convexa, lo que hará que los cálculos sean mucho más complejos. Sin embargo, creo que el peligro aquí no es significativo ya que el único caso en el que podría fallar es esto, y, francamente, no creo que ocurra a menudo (tuve problemas para encontrar este contra modelo):

  2. x e y son invertidos e y tiene un signo negativo al calcular Math.atan2 . Esto se debe a la diferencia entre cómo Math.atan2 y d3.svg.arc ven el sistema de coordenadas y la dirección de y positivo con svg .

    Sistema de Math.atan2 para Math.atan2

    θ = Math.atan2(y, x) = Math.atan2(-svg.y, x)

    Sistema de d3.svg.arc para d3.svg.arc

    θ = Math.atan2(x, y) = Math.atan2(x, -svg.y)

Pondré un elemento de texto en cada arco de mi gráfico circular (centro), como se muestra en este ejemplo: http://bl.ocks.org/mbostock/3887235

Pero solo pondré el elemento de texto si la sala es suficiente para todo el texto, por lo que debo comparar el tamaño de mi elemento de texto con el espacio "disponible" en cada arco.

Creo que puedo hacer esto con getBBox () para obtener las dimensiones del texto ... pero ¿cómo puedo obtener (y comparar) la dimensión del espacio disponible en cada arco?

Gracias...!


Realmente no se puede hacer esto con el cuadro delimitador porque el cuadro delimitador es mucho más grande que una cuña para las cuñas del gráfico circular. Es decir, aunque la cuña en el borde exterior sea lo suficientemente ancha como para acomodar el texto, eso no significa que sea lo suficientemente ancha en la posición real del texto.

Desafortunadamente, no hay una manera fácil de hacer lo que estás tratando de hacer (prueba de superposición de nivel de píxel). Ver, por ejemplo, esta pregunta para obtener más información. Sugeriría simplemente colocar las etiquetas de texto fuera del gráfico circular para que no se encuentre con este problema.