我有以下代码绘制了一个非常简单的树。单击任何节点后,我将调用带有新数据的update函数,以在树的底部添加一个新的子代。
已添加新节点,但兄弟节点不会更新其位置。
如果我注销节点:
var nodes = root.descendants();
console.log(nodes);
我可以看到位置x,y已经正确更新,但是在上一个节点没有移动位置的情况下,我得到了重叠效果。
我在这里做错了什么
<!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>
答案 0 :(得分:0)
在D3数据绑定(d3.select(s).data(d)
)中,我们应该准备做三件事:
enter
,它为数据中尚未选择的DOM中的每个元素添加了一个几何图形,
transition
,它使用新数据更改DOM中的每个选定元素,并且
exit
,如果我们的数据少于所选DOM中的元素,则会从DOM中删除元素。
对于您而言,您只需要更新update()
函数即可执行以下三个操作:
<!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>
如果您想更多地查看数据绑定,我在这里整理了一下tutorial on data binding in D3,可能会有帮助。