example d3js biblioteca bar javascript svg d3.js force-layout

javascript - d3js - d3 reference



Muestra una punta de flecha en medio del enlace de diseƱo de fuerza D3 (3)

En lugar de colocar el marcador en un extremo, cree sus líneas ( <polyline> o <path> ) con un solo punto en el centro de la línea y use el marker-mid para aplicar las puntas de flecha.

Esta demostración para esta respuesta mía usa esta técnica para crear múltiples puntos interiores a lo largo de la ruta junto con el marker-mid . Simplemente estarías creando un único "punto de ruta" en lugar de muchos.

Edición : Aquí hay un simple truco para la demostración existente que muestra lo que quiero decir:

Demostración: http://jsfiddle.net/tk7Wv/2/

Los únicos cambios son:

  1. Cambiar marker-end del marker-mid a un marker-mid , y
  2. Modificación del código de generación de ruta para crear dos arcos (conectados en el medio) en lugar de uno.

Requerirá un poco de trigonometría simple como lo ilustra Superboggly para elegir un punto medio apropiado en función de la cantidad de inclinación que desee en sus líneas.

Estoy usando D3 para dibujar un gráfico dirigido por fuerza, que es muy similar a este ejemplo: http://bl.ocks.org/mbostock/1153292

Estoy tratando de colocar las puntas de flecha en medio de los enlaces en lugar del final.

Jugar con el attr("refX", 0) del marcador no ayuda mucho, porque es absoluto y no es relativo a la longitud del enlace; mis enlaces tienen longitudes variables.

He estado buscando en Google, y mi mejor idea fue reemplazar link.attr("marker-end", ...) con link.attr("marker-segment", ...) acuerdo con este example (busque Las cruces en el centro de las gráficas). Pero esto no parece funcionar ... ¿Supongo que porque es solo parte del borrador de SVG2 pero mi navegador admite una versión inferior? (Estoy usando la versión más reciente de Chrome por cierto).

¿Cómo puedo colocar las puntas de flecha en medio de los enlaces?


Soy el OP, esta respuesta es solo una adición a las excelentes respuestas anteriores por el bien de otros con la misma pregunta.

Las respuestas muestran cómo lograr esto para un gráfico con enlaces de arco. Si tiene enlaces directos, la respuesta aceptada debe modificarse ligeramente. Así es como:

Sus enlaces directos probablemente se implementen con la line , deben convertirse en polyline . Al igual que:

// old: svg.selectAll(".link").data(links).enter().append("line") svg.selectAll(".link").data(links).enter().append("polyline")

Luego tenemos que codificar la polilínea de acuerdo con este example , de modo que su código original que codifica la line :

force.on("tick", function() { link.attr("x1", function(d) {return d.source.x;}) .attr("y1", function(d) {return d.source.y;}) .attr("x2", function(d) {return d.target.x;}) .attr("y2", function(d) {return d.target.y;});

Cambios en:

force.on("tick", function() { link.attr("points", function(d) { return d.source.x + "," + d.source.y + " " + (d.source.x + d.target.x)/2 + "," + (d.source.y + d.target.y)/2 + " " + d.target.x + "," + d.target.y; });

Y por último, no te olvides de convertir el marker-end de marker-mid :

// old: link.attr("marker-end", link.attr("marker-mid",

Créditos a @Phrogz por mostrar el camino.


Tomé un enfoque ligeramente diferente de Phrogz. Intenté quitar el marcador de la ruta y, en cambio, dibujarlo utilizando una nueva ruta que va al punto medio del arco y cuyo trazo es invisible. Calcular el punto medio es un poco delicado, por lo que si desea cambiar las características del arco, es posible que tenga un mejor enfoque con el enfoque de Phrogz, o con algún híbrido.

En este caso, el disparo no es tan malo porque si lo observa con atención, notará que el arco utilizado para generar los enlaces proviene de un círculo con el mismo radio y la distancia entre los nodos. Así que tienes un triángulo equilátero y todo lo que necesitas hacer es calcular la distancia que pasa desde el punto medio del segmento de la línea de enlace hasta el punto medio del arco.

Creo que necesito un diagrama para explicar:

Entonces, el triángulo ABC es equilátero y la bisectriz de la CE AB Como tenemos coordenadas para A y B, encontrar M es fácil (promediar las coordenadas). Significa que también conocemos la pendiente de A a B (delta y / delta x), por lo que la pendiente de M a E es la inversa negativa. Saber M y la pendiente a E significa que casi estamos allí, solo necesitamos saber hasta dónde llegar.

Para hacer eso, usamos el hecho de que ACM es un triángulo 30-60-90 y así

| CM | = sqrt (3) * | AM |

pero | AM | = | AB | / 2 y | CE | = | AB |

Asi que

| ME | = | AB | - sqrt (3) * | AB | / 2

Para que esta longitud tenga sentido, tendremos que normalizarla con la longitud del vector de pendiente, que ya sabemos es la misma que el radio del círculo.

De todos modos, al juntarlo todo obtienes:

var markerPath = svg.append("svg:g").selectAll("path.marker") .data(force.links()) .enter().append("svg:path") .attr("class", function(d) { return "marker_only " + d.type; }) .attr("marker-end", function(d) { return "url(#" + d.type + ")"; }); ... later in the tick handler markerPath.attr("d", function(d) { var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = Math.sqrt(dx * dx + dy * dy); // We know the center of the arc will be some distance perpendicular from the // link segment''s midpoint. The midpoint is computed as: var endX = (d.target.x + d.source.x) / 2; var endY = (d.target.y + d.source.y) / 2; // Notice that the paths are the arcs generated by a circle whose // radius is the same as the distance between the nodes. This simplifies the // trig as we can simply apply the 30-60-90 triangle rule to find the difference // between the radius and the distance to the segment midpoint from the circle // center. var len = dr - ((dr/2) * Math.sqrt(3)); // Remember that is we have a line''s slope then the perpendicular slope is the // negative inverse. endX = endX + (dy * len/dr); endY = endY + (-dx * len/dr); return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + endX + "," + endY; });

Compruébalo here . Tenga en cuenta que mi ruta css para la ruta del marcador está configurada en rojo transparente, normalmente querría establecer el trazo en ''ninguno'' para ocultar las líneas.