如何删除 D3 强制布局中的节点?
How to remove node in D3 force layout?
我有一个简单的 D3 模拟,看起来像这样
当我单击 'remove 1 and 4' 按钮时,我想从模拟中删除节点 1 和 4。然而,结果如下:
从视觉上看,它似乎删除了 3 和 4(不是 1 和 4)。
我的代码如下。我需要做什么才能使这项工作正常进行?
我假设我从根本上误解了更新节点在 d3 中的工作方式。任何帮助表示赞赏。
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
<body>
<button>remove 1 and 4</button>
<script>
var width = 400,
height = 400;
var nodes = [1, 2, 3, 4].map(function(x) { return { name: x}});
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
.linkDistance(30)
.charge(-500)
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var content = svg.append("g");
var nodesData = force.nodes(),
nodeElement = content.selectAll(".node");
function tick() {
nodeElement.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
d3.selectAll('button').on('click', function() {
//remove 1 and 4
nodesData = [
nodesData[1],
nodesData[2]
]
refresh();
});
var WIDTH = 100;
//
// this logic is slightly modified from http://bl.ocks.org/tgk/6068367
//
function refresh() {
force.nodes(nodesData)
nodeElement = nodeElement.data(nodesData);
var nodeGroup = nodeElement.enter()
.append('g')
.attr("class", "node");
// node text
nodeGroup.append("text")
.attr("class", "nodetext")
.attr("dx", WIDTH/2)
.attr("dy", "14px")
.text(function(n) { return 'node '+n.name })
nodeElement.exit().remove();
force.start();
}
refresh();
</script>
您可以通过在 refresh
函数内的 .data
调用中添加一个 "key" 函数来解决您的问题:nodeElement = nodeElement.data(nodesData, function(d){ return d.name });
.
您看到的问题并非特定于更新节点。通常,选择基于数据数组的索引进行。因此,如果第一个 D3 具有 [a,b,c,d]
,现在它具有 [a,d]
,它将采用前两个元素 ([a,b]
),除非您告诉它定义数组中每个项目的键。这就是上面的函数所做的。
有关更多信息,请参阅 https://github.com/d3/d3-selection/blob/master/README.md#selection_data
我有一个简单的 D3 模拟,看起来像这样
当我单击 'remove 1 and 4' 按钮时,我想从模拟中删除节点 1 和 4。然而,结果如下:
从视觉上看,它似乎删除了 3 和 4(不是 1 和 4)。
我的代码如下。我需要做什么才能使这项工作正常进行?
我假设我从根本上误解了更新节点在 d3 中的工作方式。任何帮助表示赞赏。
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
<body>
<button>remove 1 and 4</button>
<script>
var width = 400,
height = 400;
var nodes = [1, 2, 3, 4].map(function(x) { return { name: x}});
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
.linkDistance(30)
.charge(-500)
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var content = svg.append("g");
var nodesData = force.nodes(),
nodeElement = content.selectAll(".node");
function tick() {
nodeElement.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
d3.selectAll('button').on('click', function() {
//remove 1 and 4
nodesData = [
nodesData[1],
nodesData[2]
]
refresh();
});
var WIDTH = 100;
//
// this logic is slightly modified from http://bl.ocks.org/tgk/6068367
//
function refresh() {
force.nodes(nodesData)
nodeElement = nodeElement.data(nodesData);
var nodeGroup = nodeElement.enter()
.append('g')
.attr("class", "node");
// node text
nodeGroup.append("text")
.attr("class", "nodetext")
.attr("dx", WIDTH/2)
.attr("dy", "14px")
.text(function(n) { return 'node '+n.name })
nodeElement.exit().remove();
force.start();
}
refresh();
</script>
您可以通过在 refresh
函数内的 .data
调用中添加一个 "key" 函数来解决您的问题:nodeElement = nodeElement.data(nodesData, function(d){ return d.name });
.
您看到的问题并非特定于更新节点。通常,选择基于数据数组的索引进行。因此,如果第一个 D3 具有 [a,b,c,d]
,现在它具有 [a,d]
,它将采用前两个元素 ([a,b]
),除非您告诉它定义数组中每个项目的键。这就是上面的函数所做的。
有关更多信息,请参阅 https://github.com/d3/d3-selection/blob/master/README.md#selection_data