2011-12-29 43 views
22

Tôi đã làm việc trên đồ thị được điều chỉnh lực và có một số vấn đề với việc thêm văn bản/nhãn vào các liên kết trong đó các liên kết không được căn chỉnh đúng với các nút. Làm thế nào để sửa chữa nó?Thêm văn bản/nhãn vào các liên kết trong đồ thị lực D3 theo hướng

Và cách tôi có thể thêm trình xử lý sự kiện vào phần tử văn bản SVG? Thêm .on("dblclick",function(d) {....} không hoạt động.

Dưới đây là đoạn mã:

<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> 

Trả lời

17

Bạn đã thử nghiệm với việc tạo ra các yếu tố văn bản riêng biệt trong một độc lập (đơn giản) ví dụ? Nó sẽ cung cấp cho bạn một cảm giác tốt hơn về cách các thuộc tính khác nhau kiểm soát vị trí.

Đối với liên kết dọc, sử dụng "dy" thuộc tính:

  • theo mặc định, các cơ sở của văn bản là nguồn gốc (từ dưới thẳng hàng)
  • một dy của .35em trung tâm văn bản theo chiều dọc
  • một dy của .72em đặt đường xương sống của văn bản ở xứ hàng hóa (top-aligned)

Sử dụng đơn vị em là tốt đẹp vì nó sẽ mở rộng quy mô tự động dựa trên kích thước phông chữ. Nếu bạn không chỉ định đơn vị (chẳng hạn như -20 trong mã của bạn), nó sẽ mặc định là pixel.

Đối với liên kết ngang, sử dụng "text-neo" thuộc tính:

  • mặc định là "bắt đầu" (canh trái cho các ngôn ngữ từ trái sang phải)
  • "giữa"
  • "end"

Ngoài ra còn có thuộc tính "dx", đó là hấp dẫn để sử dụng cho đệm. Tuy nhiên, tôi sẽ không khuyên bạn nên nó bởi vì có một lỗi trong Firefox và Opera mà làm cho nó không hoạt động như mong đợi kết hợp với văn bản neo giữa hoặc kết thúc.

-1

Chỉ cần thêm dòng này:

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

vào mã sau dòng:

node.append("svg:text") 

nó sẽ giống như thế này:

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

này sẽ tập trung văn bản trong một nút, nhưng tôi tin rằng các câu hỏi được hỏi giữa văn bản trên một liên kết. – dchang

5

Tôi đang sử dụng một vòm như một liên kết giữa các nút với văn bản nhãn được đặt ở giữa. Dưới đây là một đoạn mã:

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

Sử dụng một ví dụ nhỏ bên ngoài của D3 để xem làm thế nào những thứ SVG hoạt động. Sau đó, chỉ cần xây dựng lại cấu trúc này bằng cách sử dụng D3 và dữ liệu tùy chỉnh của bạn.

<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

Giống như 'textPath', SVG phân biệt chữ hoa chữ thường (ít nhất là trong Chrome), vì vậy thuộc tính nên đọc' startOffset'. –

+1

Cảm ơn bạn đã chỉ ra, tôi đã cập nhật câu trả lời của mình. – Jack

10

Created JS dụ fiddle cho thấy nhãn trên các liên kết trong biểu đồ bố trí Buộc D3

Xem bản demo làm việc trong JS Fiddle: http://jsfiddle.net/bc4um7pc/

Cho Id để đường dẫn của bạn như dưới đây

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

Sử dụng phần tử SVG textPath để liên kết nhãn với các liên kết ở trên bằng cách chỉ định Thuộc tính 'xlink: href' trỏ đến liên kết/đường dẫn tương ứng.

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 
    }); 
Các vấn đề liên quan