Agregue texto / etiqueta a los enlaces en el gráfico dirigido por la fuerza D3

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

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

Aquí está el fragmento de código:

  .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; }  
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 dx; }) .attr("y", function(d) { return dy; }) .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(" + dx + "," + dy + ")"; }); }); function redraw() { vis.attr("transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")"); };

enter image description here

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

                   Centered edge label     

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

Para la alineación vertical, use el atributo “dy”:

  • de forma predeterminada, la línea base del texto está en el origen (alineado a la parte inferior)
  • una dy de .35em centra el texto verticalmente
  • un dy de .72em coloca la línea superior del texto en el origen (alineado por la parte superior)

Usar em units es bueno porque se escalará 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, use el atributo “anclar texto”:

  • el valor predeterminado es “inicio” (alineado a la izquierda para idiomas de izquierda a derecha)
  • “medio”
  • “fin”

También está 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.

Ejemplo de JS Fiddle creado para mostrar tags sobre enlaces en D3 Tabla de diseño forzado

Ver demostración funcional en JS Fiddle: http://jsfiddle.net/bc4um7pc/

Dale Id a tu camino como abajo

 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 tags con enlaces de arriba especificando su atributo ‘xlink: href’ 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 }); 

Estoy usando un arco como un enlace entre nodos con un texto de etiqueta colocado en el medio. Aquí hay 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(" + dx + "," + dy + ")"; }); } 

Solo agregue esta línea:

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

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

 node.append("svg:text") 

Debe tener un aspecto como este:

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