2011-12-29 17 views
22

He estado trabajando en gráficos de fuerza dirigida y tengo algunos problemas para agregar texto/etiqueta en enlaces donde los enlaces no están alineados correctamente con los nodos. ¿Como arreglarlo?Agregue texto/etiqueta en enlaces en el gráfico dirigido a fuerza D3

¿Y cómo puedo agregar un detector de eventos a un elemento de texto SVG? Agregar .on("dblclick",function(d) {....} simplemente no funciona.

He aquí el fragmento de código:

<style type="text/css"> 
    .link { stroke: #ccc; } 
    .routertext { pointer-events: none; font: 10px sans-serif; fill: #000000; } 
    .routertext2 { pointer-events: none; font: 9px sans-serif; fill: #000000; } 
    .linktext { pointer-events: none; font: 9px sans-serif; fill: #000000; } 
</style> 

<div id="canvas"> 
</div> 

<script type="text/javascript" src="d3/d3.js"></script> 
<script type="text/javascript" src="d3/d3.layout.js"></script> 
<script type="text/javascript" src="d3/d3.geo"></script> 
<script type="text/javascript" src="d3/d3.geom.js"></script> 


<script type="text/javascript"> 

var w = 960, 
    h = 600, 
    size = [w, h]; // width height  
var vis = d3.select("#canvas").append("svg:svg") 
    .attr("width", w) 
    .attr("height", h) 
    .attr("transform", "translate(0,0) scale(1)") 
    .call(d3.behavior.zoom().on("zoom", redraw)) 
    .attr("idx", -1) 
    .attr("idsel", -1) 
    ; 

var routers = { 
    nodes: [ 
     {id:0, name:"ROUTER-1", group:1, ip: "123.123.123.111", 
      x:394.027, y:450.978,outif:"ge-0/1/0.0",inif:""}, 
     {id:1, name:"ROUTER-2", group:1, ip: "123.123.123.222", 
      x:385.584, y:351.513,outif:"xe-4/2/0.0",inif:"ge-5/0/3.0"}, 
     {id:2, name:"ROUTER-3", group:1, ip: "123.123.123.333", 
      x:473.457, y:252.27,outif:"ae1.0",inif:"xe-1/0/1.0"}, 
     {id:3, name:"ROUTER-4", group:2, ip: "123.123.123.444", 
      x:723.106, y:266.569,outif:"as0.0",inif:"ae1.0"}, 
     {id:4, name:"ROUTER-5", group:3, ip: "123.123.123.555", 
      x:728.14, y:125.287,outif:"so-4/0/2.0",inif:"as1.0"}, 
     {id:5, name:"ROUTER-6", group:3, ip: "123.123.123.666", 
      x:738.975, y:-151.772,outif:"",inif:"PO0/2/2/1" } 
    ], 
    links: [ 
     {source:0, target:1, value:3, name:'link-1',speed:"1000mbps", 
      outif:"ge-0/1/0.0",nextif:"ge-5/0/3.0"}, 
     {source:1, target:2, value:3, name:'link-2',speed:"10Gbps", 
      outif:"xe-4/2/0.0",nextif:"xe-1/0/1.0"}, 
     {source:2, target:3, value:3, name:'link-3',speed:"20Gbps", 
      outif:"ae1.0",nextif:"xe-1/2/1.0"}, 
     {source:3, target:4, value:3, name:'link-4',speed:"1Gbps", 
      outif:"as0.0",nextif:"as1.0"}, 
     {source:4, target:5, value:3, name:'link-5',speed:"OC3", 
      outif:"so-4/0/2.0",nextif:"PO0/2/2/1"} 
    ] 
}; 

var force = d3.layout.force() 
     .nodes(routers.nodes) 
     .links(routers.links) 
     .gravity(0) 
     .distance(100) 
     .charge(0) 
     .size([w, h]) 
     .start(); 

var link = vis.selectAll("g.link") 
     .data(routers.links) 
     .enter().append("svg:g"); 

    link.append("svg:line") 
     .attr("class", "link") 
     .attr("title", function(d) { return "From: "+d.outif+", To: "+d.nextif }) 
     .attr("style", "stroke:#00d1d6;stroke-width:4px") 
     .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; }); 

    link.append("svg:text") 
     .attr("class", "linktext") 
     .attr("dx", function(d) { return d.source.x; }) 
     .attr("dy", function(d) { return d.source.y; }) 
     .text("some text to add..."); 

    var node = vis.selectAll("g.node") 
     .data(routers.nodes) 
    .enter() 
     .append("svg:g") 
     .attr("id", function(d) { return d.id;}) 
     .attr("title", function(d) {return d.ip}) 
     .attr("class", "node") 
     .attr("x", function(d) { return d.x; }) 
     .attr("y", function(d) { return d.y; }) 
     .on("dblclick",function(d) { 
      alert('router double-clicked'); d3.event.stopPropagation(); 
     }) 
     .on("mousedown", function(d) { 
      if (d3.event.which==3) { 
       d3.event.stopPropagation(); 
       alert('Router right-clicked'); 
      } 
     }) 
     .call(force.drag); 

    node.append("svg:image") 
     .attr("class", "node") 
     .attr("xlink:href", "router.png") 
     .attr("x", -24) 
     .attr("y", -18) 
     .attr("width", 48) 
     .attr("height", 36); 

    node.append("svg:text") 
     .attr("class", "routertext") 
     .attr("dx", -30) 
     .attr("dy", 20) 
     .text(function(d) { return d.name }); 

    node.append("svg:text") 
     .attr("class", "routertext2") 
     .attr("dx", 0) 
     .attr("dy", -20) 
     .attr("title", "some title to show....") 
     .text(function(d) { return d.outif }) 
     .on("click", function(d,i) {alert("outif text clicked");}) 
     .call(force.drag); 

    node.append("svg:text") 
     .attr("class", "routertext2") 
     .attr("dx", -40) 
     .attr("dy", 30) 
     .text(function(d) { return d.inif }); 

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

    node.attr("transform", function(d) { 
     return "translate(" + d.x + "," + d.y + ")"; }); 
    }); 

    function redraw() { 
    vis.attr("transform", 
     "translate(" + d3.event.translate + ")" 
     + "scale(" + d3.event.scale + ")"); 
    }; 

</script> 

Respuesta

17

¿Ha experimentado con la creación de elementos de texto por separado en un (simple) Ejemplo independiente? Debería darle una mejor idea de cómo los diferentes atributos controlan el posicionamiento.

Para la alineación vertical, utilizar el atributo "dy":

  • por defecto, la línea de base del texto está en el origen (parte inferior alineados)
  • un dy de .35em centra el texto verticalmente
  • un dy de .72em coloca la línea superior del texto en el origen (top-alineados)

Usando unidades em es agradable porque se escala automáticamente en función del tamaño de la fuente. Si no especifica unidades (como -20 en su código), su valor predeterminado es píxeles.

para la alineación horizontal, utilice el atributo "text-ancla":

  • el valor predeterminado es "start" (alineado a la izquierda para los idiomas de derecha a izquierda a)
  • "medio"
  • "fin"

También existe el atributo "dx", que es tentador usar para el relleno. Sin embargo, no lo recomendaría porque hay un error en Firefox y Opera que hace que no funcione como se esperaba junto con text-anchor middle or end.

-1

Sólo tiene que añadir esta línea:

.attr("text-anchor", "middle") 

al código después de la línea:

node.append("svg:text") 

que debería tener este aspecto:

node.append("svg:text") 
.attr("text-anchor", "middle") 
...... 
+1

Esto centrará el texto dentro de un nodo, pero creo que la pregunta está pidiendo a centrar el texto en un enlace. – dchang

5

estoy usando un arco como enlace entre nodos con un texto de etiqueta colocado en el medio. Aquí es un fragmento de código:

var vis = d3.select("body") 
    .append("svg") 
    .attr("width", 600) 
    .attr("height", 400) 
    .append("g"); 

    var force = d3.layout.force() 
    .gravity(.05) 
    .distance(120) 
    .charge(-100) 
    .size([600, 400]); 
    var nodes = force.nodes(), links = force.links(); 

    // make an arch between nodes and a text label in the middle 
    var link = vis.selectAll("path.link").data(links, function(d) { 
     return d.source.node_id + "-" + d.target.node_id; }); 
    link.enter().append("path").attr("class", "link"); 

    var linktext = vis.selectAll("g.linklabelholder").data(links); 
    linktext.enter().append("g").attr("class", "linklabelholder") 
    .append("text") 
    .attr("class", "linklabel") 
    .attr("dx", 1) 
    .attr("dy", ".35em") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return "my label" }); 

    // add your code for nodes .... 

    force.on("tick", tick); force.start(); 

    function tick() { 
    // curve 
    link.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); 
    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," 
     + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
    });  
    // link label 
    linktext.attr("transform", function(d) { 
     return "translate(" + (d.source.x + d.target.x)/2 + "," 
     + (d.source.y + d.target.y)/2 + ")"; }); 
    // nodes 
    node.attr("transform", function(d) { 
     return "translate(" + d.x + "," + d.y + ")"; }); 
    } 
18

enter image description here

usar un ejemplo más pequeño fuera del D3 para ver cómo funciona la materia SVG. Luego, simplemente reconstruya esta estructura usando D3 y sus datos personalizados.

<html> 
    <body> 

<svg width="600px" height="400px"> 

    <defs> 
     <!-- DEFINE AN ARROW THAT WE CAN PLACE AT THE END OF EDGES. --> 
     <!-- USE REFX TO MOVE THE ARROW'S TIP TO THE END OF THE PATH. --> 
     <marker 
      orient="auto" 
      markerHeight="12" 
      markerWidth="12" 
      refY="0" 
      refX="9" 
      viewBox="0 -5 10 10" 
      id="ARROW_ID" 
      style="fill: red; fill-opacity: 0.5;"> 

      <path d="M0, -5L10, 0L0, 5"></path> 

     </marker> 
    </defs> 

    <!-- DEFINE A PATH. SET ITS END MARKER TO THE ARROW'S ID. --> 
    <!-- SET FILL NONE TO DRAW A LINE INSTEAD OF A SHAPE. --> 
    <path 
     d="M100,100 A300,250 0 0,1 500,300" 
     style="fill:none; stroke:grey; stroke-width:2px;" 
     id="PATH_ID" 
     marker-end="url(#ARROW_ID)" /> 

    <!-- DEFINE A TEXT ELEMENT AND SET FONT PROPERTIES. --> 
    <!-- USE DY TO MOVE TEXT ABOVE THE PATH. --> 
    <text 
     style="text-anchor:middle; font: 16px sans-serif;" 
     dy="-12"> 

     <!-- DEFINE A TEXT PATH FOLLOWING THE PATH DEFINED ABOVE. --> 
     <!-- USE STARTOFFSET TO CENTER TEXT. --> 
     <textPath 
      xlink:href="#PATH_ID" 
      startOffset="50%">Centered edge label</textPath> 
    </text> 

</svg> 

    </body> 
</html> 
+0

Al igual que con 'textPath', SVG distingue entre mayúsculas y minúsculas (al menos en Chrome), por lo que el atributo debe leer' startOffset'. –

+1

Gracias por señalar, actualicé mi respuesta. – Jack

10

Creado ejemplo violín de JS para mostrar las etiquetas a través de enlaces en la carta diseño D3 forzado

Ver demostración de trabajo en JS violín: http://jsfiddle.net/bc4um7pc/

Dale Id de a la ruta, como a continuación

var path = svg.append("svg:g").selectAll("path") 
    .data(force.links()) 
    .enter().append("svg:path") 
    .attr("class", function(d) { return "link " + d.type; }) 
    .attr("id",function(d,i) { return "linkId_" + i; }) 
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; }); 

Utilice el elemento SVG textPath para asociar etiquetas con enlaces de arriba especificando su 'xlink: href' atributo para apuntar a su respectivo enlace/ruta.

var linktext = svg.append("svg:g").selectAll("g.linklabelholder").data(force.links()); 
    linktext.enter().append("g").attr("class", "linklabelholder") 
    .append("text") 
    .attr("class", "linklabel") 
    .style("font-size", "13px") 
    .attr("x", "50") 
    .attr("y", "-20") 
    .attr("text-anchor", "start") 
    .style("fill","#000") 
    .append("textPath") 
    .attr("xlink:href",function(d,i) { return "#linkId_" + i;}) 
    .text(function(d) { 
     return "my text"; //Can be dynamic via d object 
    }); 
Cuestiones relacionadas