Mostrar una cabeza de flecha en el centro de D3 fuerza de enlace diseño

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

Estoy tratando de colocar las puntas de flecha en el medio de los enlaces en vez de al final.

Jugando con el attr("refX", 0) de que el marcador no ayuda mucho, porque es absoluta y no relativa a la longitud de vínculo – mis enlaces tienen diferentes longitudes.

He estado googleando todo, y lo mejor de mi idea era reemplazar link.attr("marker-end", ...) con link.attr("marker-segment", ...) de acuerdo a este ejemplo (busque las cruces en el medio de los gráficos). Pero esto no parece funcionar.. supongo que porque es parte de SVG2 proyecto, pero mi navegador es compatible con una versión inferior? (Yo estoy usando la más reciente versión de Chrome, por cierto).

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

Es importante tener en cuenta que la marker-mid atributo sólo tiene efecto si la ruta de acceso tiene los vértices entre el inicio/final.

OriginalEl autor talkol | 2013-03-31

3 Kommentare

  1. 19

    Lugar de colocar el marcador en fin, crear sus líneas (<polyline> o <path>) con un único punto en el medio de la línea y el uso de en el marcador a mediados para aplicar las puntas de flecha.

    Esta demo para esta respuesta de la mina utiliza esta técnica para crear varios puntos del interior a lo largo de la longitud de un camino junto con marker-mid. Sólo tendría que ser la creación de un único «punto de referencia» en lugar de muchos.

    Editar: he Aquí un simple hack a los existentes en la demo que muestra lo que quiero decir:

    Demo: http://jsfiddle.net/tk7Wv/2/

    Mostrar una cabeza de flecha en el centro de D3 fuerza de enlace diseño

    Los únicos cambios son:

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

    Se requerirá un poco de simple trigonometría como Superboggly ilustra a elegir un apropiado punto medio sobre la base del importe de la reverencia que usted desea en sus líneas.

    Gracias, excelente respuesta. Mi gráfico de hecho había algunos recta enlaces (hecho con la línea). De acuerdo a tu sugerencia, he cambiado en polilíneas y se añade un punto en el medio. A continuación, en el marcador de mediados y trabajó como un encanto.
    Añadido otra respuesta para reflejar esto para los demás 🙂
    ¿Qué acerca de la diagonal o banzir curva ?
    Versiones específicas de JSFiddle no puede ser modificado; guardar los cambios siempre crea un nuevo vínculo. Es probable que el D3 de la biblioteca que me estaba cargando, ha sido actualizado, y la aplicación se añade a otros segmentos en lugar de un solo arco ahora.
    Tenga en cuenta que esto no funciona en la Versión 61.0.3163.100 de Chrome. Hace varias flechas.

    OriginalEl autor Phrogz

  2. 13

    Yo soy el OP, esta respuesta es sólo una adición a las excelentes respuestas de arriba por el bien de los demás con la misma pregunta.

    Las respuestas muestran cómo lograr esto para un gráfico con arco enlaces. Si usted tiene directamente los enlaces, los aceptados respuesta debe ser modificado ligeramente. Esta es la forma:

    Su recta enlaces son probablemente implementado con line, deben ser convertidas en polyline. Así:

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

    Entonces tenemos que codificar la polilínea de acuerdo a este ejemplo, por lo 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 olvides el convertir marker-end a marker-mid:

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

    Créditos a @Phrogz para mostrar el camino.

    Deseo que os puede votar dos veces, trabajaba como un sueño.

    OriginalEl autor talkol

  3. 10

    Me tomó un enfoque ligeramente diferente de Phrogz. He intentado quitar la ruta del marcador y en lugar de dibujar usando un nuevo camino que va a la del arco de medio punto y cuyo trazo es invisible. Calcular el punto medio es un poco quisquillosos así que si usted quiere cambiar las características del arco que podría ser mejor servido con Phrogz del enfoque, o algún híbrido.

    En este caso, la trigonometría no es tan malo, porque si se mira de cerca se dará cuenta de que el arco se utiliza para generar los enlaces son de un círculo con el mismo radio y la distancia entre los nodos. Así que usted tiene un triángulo equilátero y todo lo que usted necesita hacer es calcular la distancia de pasado el punto medio de la línea de vínculo segmento de arco de medio punto.

    Creo que necesito un diagrama para explicar:

    Mostrar una cabeza de flecha en el centro de D3 fuerza de enlace diseño
    Así que el triángulo ABC es equilátero y CE bisecar AB. Ya tenemos las coordenadas de a y B, hallar M es fácil (promedio de las coordenadas). Significa también sabemos que la pendiente de la a a la B (delta y /delta x) de modo que la pendiente de la M a E es el negativo de la inversa. Saber M y la pendiente a de la E significa que estamos casi allí, sólo tenemos que saber cómo de lejos para ir.

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

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

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

    Así

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

    Para que esta longitud de hacer sentido tenemos que normalizar con la longitud de la pendiente del vector, que ya sabemos que es el mismo que el círculo de radio.

    De todos modos, poniendo todo junto:

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

    Check it out aquí. Tenga en cuenta que mi camino css para el marcador de la ruta de acceso se establece en un rojo transparente, normalmente usted quiere trazo establecido en «none» para ocultar las líneas.

    Gran explicación y esfuerzo para ofrecer un ejemplo de trabajo. Yo prefiero el uso de marcadores, pero me gustaría darle más de +1 si podía.
    Gracias! Realmente creo que la polilínea es más generalmente flexible, pero me gusta ser capaz de utilizar la ruta de acceso arc. Así que me siento una combinación de nuestras soluciones podría funcionar muy bien.
    Oh, pero usted puede fácilmente usar una ruta de acceso arc con mediados de marcador: sólo dividir en dos arcos de ir a la mitad cada uno.
    Sí! – pero entonces usted todavía tiene que calcular que el arco de medio punto, que en realidad es más de lo que mi explicación. Por eso creo que podría funcionar bien junto con su solución.
    En la segunda la gran explicación y el diagrama! Impresionante trabajo! Yo terminé eligiendo el método alternativo (con marcador-mid), pero esta fue una impresionante respuesta de todos modos.

    OriginalEl autor Superboggly

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea