添加新的同级树时,树未更新节点位置 [英] Tree not updating nodes position when adding a new sibling
问题描述
我有以下代码绘制了一个非常简单的树.单击任何节点后,我将调用带有新数据的update函数,以在树的底部添加一个新的子代.
I have the following code which draws a very simple tree. On clicking any node I'm calling the update function with new data to add a new child at the bottom of the tree.
已添加新节点,但兄弟节点不会更新其位置.
The new node is added but the sibling node does not update it's position.
如果我注销节点:
var nodes = root.descendants();
console.log(nodes);
我可以看到位置x,y已正确更新,但是在上一个节点未移动位置的情况下,我得到了重叠效果.
I can see that the position x,y has been correctly updated but I get an overlapping effect where the previous node has not moved position.
我在这里做错了什么
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title></title>
</head>
<style>
.node {
fill: #fff;
stroke: steelblue;
cursor: pointer;
}
.link {
fill: none;
stroke: #ddd;
stroke-width: 2px;
}
</style>
<body>
<svg width="1500" height="920">
<g transform="translate(550, 100)">
<g class="links"></g>
<g class="nodes"></g>
</g>
</svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>
var treeData = {
"name": "root",
"children": [
{
"name": "ORIG"
}
]
}
var treeLayout = d3.tree()
.size([900, 200])
.nodeSize([210, 40])
function update(data) {
var root = d3.hierarchy(data);
treeLayout(root);
var nodes = root.descendants();
var links = root.links();
var nodeWidth = 190;
var nodeHeight = 90;
nodes.forEach(function (d) {
d.y = d.depth * 170;
});
// Nodes
const nodesEnter = d3.select('.nodes')
.selectAll('.node')
.data(nodes)
.enter()
.append('rect')
.classed('node', true)
.attr("width", 190)
.attr("height", 90)
.attr('x', function(d) {return d.x;})
.attr('y', function(d) {return d.y;})
.on("click", click);
// Links
d3.select('.links')
.selectAll('.link')
.data(links)
.enter()
.append('line')
.classed('link', true)
.attr('x1', function(d, i) {return d.source.x + (nodeWidth / 2);})
.attr('y1', function(d) {return d.source.y + (nodeHeight);})
.attr('x2', function(d) {return d.target.x + (nodeWidth / 2);})
.attr('y2', function(d) {return d.target.y + 0;});
function click(d) {
update({
"name": "root",
"children": [
{
"name": "ORIG"
},
{
"name": "NEW"
}
]
});
}
}
update(treeData);
</script>
</body>
</html>
推荐答案
在D3数据绑定(d3.select(s).data(d)
)中,我们应该准备做三件事:
In a D3 data binding (d3.select(s).data(d)
), we should be prepared to do 3 things:
-
enter
,它为数据中尚未包含所选DOM的每个元素添加了一个几何图形,
enter
, which adds a geom for each element in our data that's not yet in the selected DOM,
transition
,它使用新数据更改DOM中的每个选定元素,并且
transition
, which changes each selected element in the DOM using the new data, and
exit
,如果我们的数据少于所选DOM中的元素,它将从DOM中删除元素.
exit
, which removes elements from the DOM if we have less data than elements in the selected DOM.
对于您而言,您只需要更新您的update()
函数即可执行以下三个操作:
In your case, you just need to update your update()
function to perform each of these three actions:
<!DOCTYPE html>
<meta charset="utf-8">
<head></head>
<style>
.node {
fill: #fff;
stroke: steelblue;
cursor: pointer;
}
.link {
fill: none;
stroke: #ddd;
stroke-width: 2px;
}
</style>
<body>
<svg width="1500" height="920">
<g transform="translate(550, 100)">
<g class="links"></g>
<g class="nodes"></g>
</g>
</svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>
var treeData = {
"name": "root",
"children": [
{
"name": "ORIG"
}
]
}
var treeLayout = d3.tree()
.size([900, 200])
.nodeSize([210, 40])
function update(data) {
var root = treeLayout(d3.hierarchy(data)),
nodes = root.descendants(),
links = root.links(),
nodeWidth = 190,
nodeHeight = 90;
nodes.forEach(d => d.y = d.depth * 170)
// Nodes
const node = d3.select('.nodes').selectAll('.node').data(nodes)
node.enter()
.append('rect')
.classed('node', true)
.attr("width", 190)
.attr("height", 90)
.attr('x', d => d.x)
.attr('y', d => d.y)
.on("click", click)
node.transition()
.attr('x', d => d.x)
.attr('y', d => d.y)
node.exit()
.remove()
// Links
const link = d3.select('.links').selectAll('.link').data(links)
link.enter()
.append('line')
.classed('link', true)
.attr('x1', d => d.source.x + (nodeWidth / 2))
.attr('y1', d => d.source.y + (nodeHeight))
.attr('x2', d => d.target.x + (nodeWidth / 2))
.attr('y2', d => d.target.y)
link.transition()
.attr('x1', d => d.source.x + (nodeWidth / 2))
.attr('y1', d => d.source.y + (nodeHeight))
.attr('x2', d => d.target.x + (nodeWidth / 2))
.attr('y2', d => d.target.y)
link.exit()
.remove()
function click(d) {
update({
"name": "root",
"children": [
{
"name": "ORIG"
},
{
"name": "NEW"
}
]
});
}
}
update(treeData);
</script>
</body>
</html>
如果您想更多地查看数据绑定,我会整理一下有关D3中数据绑定的教程,这可能会有所帮助.
If you want to review data bindings more, I put together a little tutorial on data binding in D3 here that may help.
这篇关于添加新的同级树时,树未更新节点位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!