2012-03-05 50 views
34

Tôi mới đến D3 và gặp khó khăn trong việc thiết lập giới hạn cho bố cục lực lượng của tôi. Tôi đã xoay xở với nhau (từ ví dụ) những gì tôi muốn, nhưng tôi cần đồ thị để chứa đựng. Trong chức năng đánh dấu, một biến đổi/dịch sẽ hiển thị biểu đồ của tôi một cách chính xác, nhưng khi tôi sử dụng cx và cy với Math.max/min (Xem mã nhận xét), các nút được ghim vào góc trên cùng bên trái trong khi các dòng được chứa đúng cách .D3 bố trí lực hướng với hộp giới hạn

Đây là những gì tôi có bên dưới ... tôi đang làm gì sai?

var w=960, h=500, r=8, z = d3.scale.category20(); 

var color = d3.scale.category20(); 

var force = d3.layout.force() 
     .linkDistance(function(d) { return (d.value*180) }) 
     .linkStrength(function(d) { return (1/(1+d.value)) }) 
     .charge(-1000) 
     //.gravity(.08) 
     .size([w, h]); 

var vis = d3.select("#chart").append("svg:svg") 
     .attr("width", w) 
     .attr("height", h) 
     .append("svg:g") 
     .attr("transform", "translate(" + w/4 + "," + h/3 + ")"); 

vis.append("svg:rect") 
    .attr("width", w) 
    .attr("height", h) 
    .style("stroke", "#000"); 


d3.json("miserables.json", function(json) { 

     var link = vis.selectAll("line.link") 
       .data(json.links); 

     link.enter().append("svg:line") 
       .attr("class", "link") 
       .attr("x1", function(d) { return d.source.x; }) 
       .attr("y1", function(d) { return d.source.y; }) 
       .attr("x2", function(d) { return d.source.x; }) 
       .attr("y2", function(d) { return d.source.y; }) 
       .style("stroke-width", function(d) { return (1/(1+d.value))*5 }); 

     var node = vis.selectAll("g.node") 
       .data(json.nodes); 

     var nodeEnter = node.enter().append("svg:g") 
       .attr("class", "node") 
       .on("mouseover", fade(.1)) 
       .on("mouseout", fade(1)) 
       .call(force.drag); 

     nodeEnter.append("svg:circle") 
       .attr("r", r) 
       .style("fill", function(d) { return z(d.group); }) 
       .style("stroke", function(d) { return 
d3.rgb(z(d.group)).darker(); }); 

     nodeEnter.append("svg:text") 
       .attr("text-anchor", "middle") 
       .attr("dy", ".35em") 
       .text(function(d) { return d.name; }); 

     force 
     .nodes(json.nodes) 
     .links(json.links) 
     .on("tick", tick) 
     .start(); 

     function tick() { 

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

     // This contains the lines within the boundary, but the nodes are 
stuck in the top left corner 
       //node.attr("cx", function(d) { return d.x = Math.max(r, Math.min(w 
- r, d.x)); }) 
       //  .attr("cy", function(d) { return d.y = Math.max(r, Math.min(h - 
r, d.y)); }); 

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

     var linkedByIndex = {}; 

    json.links.forEach(function(d) { 
     linkedByIndex[d.source.index + "," + d.target.index] = 1; 
    }); 

     function isConnected(a, b) { 
     return linkedByIndex[a.index + "," + b.index] || 
linkedByIndex[b.index + "," + a.index] || a.index == b.index; 
    } 

     function fade(opacity) { 
     return function(d) { 
      node.style("stroke-opacity", function(o) { 
         thisOpacity = isConnected(d, o) ? 1 : opacity; 
         this.setAttribute('fill-opacity', thisOpacity); 
       return thisOpacity; 
         }); 

         link.style("stroke-opacity", opacity).style("stroke-opacity", 
function(o) { 
       return o.source === d || o.target === d ? 1 : opacity; 
       }); 
     }; 
     } 

}); 
+0

Tôi đã chơi với một số tham số và quyết định Nếu đồ thị là rất lớn nó vẫn sẽ đặt ra một vấn đề, nhưng nếu không nên chứa các nút tốt. –

Trả lời

59

Có một bounding box example trong số talk on force layouts. Vị trí Tích hợp Verlet cho phép bạn xác định các ràng buộc hình học (chẳng hạn như các hộp giới hạn và collision detection) bên trong trình lắng nghe sự kiện "đánh dấu"; chỉ cần di chuyển các nút để tuân thủ ràng buộc và mô phỏng sẽ thích ứng cho phù hợp.

Điều đó nói rằng, trọng lực chắc chắn là một cách linh hoạt hơn để giải quyết vấn đề này, vì nó cho phép người dùng kéo biểu đồ bên ngoài hộp giới hạn tạm thời và sau đó đồ thị sẽ phục hồi. Tùy thuộc vào kích thước của biểu đồ và kích thước của khu vực được hiển thị, bạn nên thử nghiệm với các cường độ tương đối khác nhau của lực hấp dẫn và phí (lực đẩy) để có được đồ thị của bạn để phù hợp.

+17

Điều quan trọng là thêm 'node.attr (" cx ", hàm (d) {return dx = Math.max (r, Math.min (width - r, dx));}) .attr (" cy " , function (d) {return dy = Math.max (r, Math.min (height - r, dy));}); ' Nếu bạn sử dụng' path' thay vì 'line', bạn sẽ cần thêm đường biên kiểm tra 'attr ('d', function() {...});' ''. – Limin

0

Mã nhận xét hoạt động trên nút, từ định nghĩa của bạn, phần tử svg g (rouping) và không hoạt động thuộc tính cx/cy. Chọn phần tử vòng tròn bên trong nút để làm cho các thuộc tính này trở nên sống động:

node.select("circle") // select the circle element in that node 
    .attr("cx", function(d) { return d.x = Math.max(r, Math.min(w - r, d.x)); }) 
    .attr("cy", function(d) { return d.y = Math.max(r, Math.min(h - r, d.y)); }); 
Các vấn đề liên quan