2016-07-27 24 views
8

Mike Bostock has an example về cách cập nhật bố cục lực. Ví dụ được dựa trên v3 - làm thế nào có thể cùng một chức năng được nhân rộng trong v4?D3 v4: Cập nhật bố cục lực

Here's my (pitiful) attempt.

Tôi đã đọc the changes cho các lựa chọn trong v4 Changelog, nhưng cuộc gọi merge vẫn còn khó hiểu. Đặc biệt, nó không rõ ràng với tôi như thế nào dữ liệu tham gia tương tác với các cuộc gọi mô phỏng nodes()links().

+0

Dường như đã được thực hiện tại https://bl.ocks.org/tezzutezzu/cd04b3f1efee4186ff42aae66c87d1a7 –

Trả lời

0

var width = 300, 
 
    height = 200; 
 

 
var color = d3.scaleOrdinal(d3.schemeCategory20); 
 

 
var nodes = [], 
 
    links = []; 
 

 
var simulation = d3.forceSimulation() 
 
    .force("link", d3.forceLink().id(function(d) { return d.id; })) 
 
    .force("charge", d3.forceManyBody()) 
 
    .force("center", d3.forceCenter(width/2, height/2)); 
 

 
var svg = d3.select("svg"); 
 

 
var linkLayer = svg.append('g').attr('id','link-layer'); 
 
var nodeLayer = svg.append('g').attr('id','node-layer'); 
 

 
// 1. Add three nodes and three links. 
 
setTimeout(function() { 
 
    var a = {id: "a"}, b = {id: "b"}, c = {id: "c"}; 
 
    nodes.push(a, b, c); 
 
    links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); 
 
    start(); 
 
}, 0); 
 

 
// 2. Remove node B and associated links. 
 
setTimeout(function() { 
 
    nodes.splice(1, 1); // remove b 
 
    links.shift(); // remove a-b 
 
    links.pop(); // remove b-c 
 
    start(); 
 
}, 2000); 
 

 
// Add node B back. 
 
setTimeout(function() { 
 
    var a = nodes[0], b = {id: "b"}, c = nodes[1]; 
 
    nodes.push(b); 
 
    links.push({source: a, target: b}, {source: b, target: c}); 
 
    start(); 
 
}, 4000); 
 

 

 
function start() { 
 
    var link = linkLayer.selectAll(".link") 
 
    .data(links, function(d) { return d.source.id + "-" + d.target.id; }); 
 
    
 
    
 
    link.enter().append("line") 
 
    .attr("class", "link"); 
 

 
    link.exit().remove(); 
 

 
    var node = nodeLayer.selectAll(".node") 
 
     .data(nodes, function(d) { return d.id;}); 
 
    
 
    node.enter().append("circle") 
 
     .attr("class", function(d) { return "node " + d.id; }) 
 
     .attr("r", 8); 
 

 
    node.exit().remove(); 
 

 
    simulation 
 
    .nodes(nodes) 
 
    .on("tick", tick); 
 

 
    simulation.force("link") 
 
    .links(links); 
 
} 
 

 
function tick() { 
 
    nodeLayer.selectAll('.node').attr("cx", function(d) { return d.x; }) 
 
     .attr("cy", function(d) { return d.y; }) 
 

 
    linkLayer.selectAll('.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; }); 
 
}
.link { 
 
    stroke: #000; 
 
    stroke-width: 1.5px; 
 
} 
 

 
.node { 
 
    fill: #000; 
 
    stroke: #fff; 
 
    stroke-width: 1.5px; 
 
} 
 

 
.node.a { fill: #1f77b4; } 
 
.node.b { fill: #ff7f0e; } 
 
.node.c { fill: #2ca02c; }
<script src="https://d3js.org/d3.v4.min.js"></script> 
 
<svg width="300px" height="200px"></svg>

Vì vậy, bạn không thực sự cần một d3 lựa chọn hợp nhất để làm cho công việc ví dụ của bạn. Lý do là vị trí nút và liên kết của bạn đang được cập nhật bởi mô phỏng. Vì vậy, bạn sẽ muốn thêm các nút và các liên kết khi bắt đầu, nhưng bất kỳ cập nhật nào cho các vị trí sẽ xảy ra ở cuối phương thức bắt đầu khi mô phỏng được bắt đầu.

Một lỗ hổng lớn với mã ban đầu của bạn là bạn được gọi là svg.selectAll ('. Node') & svg.selectAll ('. Link') ở giai đoạn đầu của tập lệnh. Khi bạn làm điều này, không có bất kỳ nút hoặc liên kết nào ràng buộc với svg, do đó bạn sẽ có được lựa chọn d3 với các phần tử DOM trống. Điều này là tốt khi bạn muốn thêm các phần tử với enter(). Append() - tuy nhiên khi loại bỏ các phần tử này sẽ không hoạt động. Sử dụng cùng, chọn d3 cũ để loại bỏ các phần tử với exit(). Remove() không hoạt động b/c không có bất kỳ phần tử DOM nào trong lựa chọn d3 để loại bỏ. Bạn cần gọi svg.selectAll() mỗi lần để lấy các phần tử DOM hiện đang có trong svg.

Tôi cũng thực hiện một vài thay đổi nhỏ trong mã của bạn. Bạn thường muốn các liên kết luôn hiển thị bên dưới các nút. Khi bạn thêm các phần tử vào SVG, các nút được thêm gần đây nhất được đặt ở trên cùng. Tuy nhiên nếu bạn thêm nhóm trước khi bàn tay (như tôi đã làm với linkLayer & nodeLayer trong mã), bất kỳ liên kết mới được thêm nào sẽ xuất hiện bên dưới bất kỳ mục nào trong nhóm nodeLayer.

Các vấn đề liên quan