[英]Enter, update and exit selections in a treemap
I have a D3 v5 treemap that I show three levels of the hierarchy via a filter.我有一个 D3 v5 树状图,我通过过滤器显示层次结构的三个级别。 Showing all levels at once would make the map too busy.一次显示所有级别会使地图太忙。 I'd like to employ a drill down or drill up feature such that when you click on a given rect (either child or parent) that re-sets that rect as the root node and then displays another three levels of the hierarchy from that new root node.我想使用向下钻取或向上钻取功能,这样当您单击给定的 rect(子项或父项)时,该 rect 将该 rect 重新设置为根节点,然后显示该新层次结构的另外三个级别根节点。
I think I'm getting the new root node data, but I can't seem to get the map to update correctly with the onclick
(the console.log in the exit().remove()
doesn't get called after the onclick).我想我正在获取新的根节点数据,但我似乎无法使用onclick
使地图正确更新( exit().remove()
中的 console.log 在 onclick 后不会被调用)。 It seems like elements are not exiting correctly, or not getting to the exit().remove()
.元素似乎没有正确退出,或者没有到达exit().remove()
。
Here is the code:这是代码:
const treemapLayout = d3.treemap()
.size([1200, 700])
.paddingOuter(16);
d3.json("test.json").then(function(data) {
// update the view
const update = (d) => {
//console.log(d)
let rootNode = d3.hierarchy(d)
console.log(rootNode)
rootNode
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || b.value - a.value; });
treemapLayout(rootNode);
let nodes = d3.select('svg g')
.selectAll('g')
.data(rootNode.descendants())
nodes
.enter()
.filter(function(d) {
return d.depth < 3;
})
.append('g')
.merge(nodes)
.attr('transform', function(d) {return 'translate(' + [d.x0, d.y0] + ')'})
//nodes
.append('rect')
.attr('width', function(d) { return d.x1 - d.x0; })
.attr('height', function(d) { return d.y1 - d.y0; })
.attr('style', function(d) {
return ('fill:' + d3.interpolateRdYlGn(d.data.health))
})
.on('click', function(d.parent) { console.log(d.data.name); update(d); })
nodes
.append('text')
.attr('dx', 4)
.attr('dy', 14)
.text(function(d) {
return d.data.name;
})
nodes
.attr('style', function(d) { console.log('here'); return d; })
.exit().remove()
};
update(data);
});
Here is the data in a simplified format:以下是简化格式的数据:
{
"name": "A1",
"health": 0.521,
"children": [
{
"name": "B1",
"health": 0.521,
"children": [
{
"name": "B1-C1",
"health": 0.614,
"children": [
{
"name": "B1-C1-D1",
"health": 0.666,
"children": [
{
"name": "B1-C1-D1-E1",
"value": 30,
"health": 0.8
},
{
"name": "B1-C1-D1-E2",
"value": 35,
"health": 0.5
},
{
"name": "B1-C1-D1-E3",
"value": 20,
"health": 0.7
}
]
},
{
"name": "B1-C1-D2",
"health": 0.45,
"children": [
{
"name": "B1-C1-D2-E1",
"value": 10,
"health": 0.8
},
{
"name": "B1-C1-D2-E1",
"value": 14,
"health": 0.1
}
]
},
{
"name": "B1-C1-D3",
"health": 0.64,
"children": [
{
"name": "B1-C1-D3-E1",
"value": 10,
"health": 0.8
},
{
"name": "B1-C1-D3-E2",
"value": 14,
"health": 0.2
},
{
"name": "B1-C1-D3-E3",
"value": 7,
"health": 0.7
},
{
"name": "B1-C1-D3-E4",
"value": 9,
"health": 0.9
},
{
"name": "B1-C1-D3-E5",
"value": 5,
"health": 0.6
}
]
},
{
"name": "B1-C1-D4",
"value": 2,
"health": 0.7
}
]
},
{
"name": "B1-C2",
"health": 0.45,
"children": [
{
"name": "B1-C2-D1",
"health": 0.45,
"value": 12
}
]
},
{
"name": "B1-C3",
"health": 0.5,
"children": [
{
"name": "B1-C3-D1",
"health": 0.5,
"value": 10
}
]
}
]
}
]
}
D3 selections are immutable . D3 选择是不可变的。
When you do this...当你这样做...
nodes.enter()
.filter(function(d) {
return d.depth < 3;
})
.append('g')
.merge(nodes)
//etc...
... the merge
is not changing what nodes
is, which is just the update selection. ... merge
不会改变nodes
是什么,这只是更新选择。
You have to reassign it:您必须重新分配它:
nodes = nodes.enter()
//etc...
Here is your code with that change (in a smaller SVG):这是带有该更改的代码(在较小的 SVG 中):
const data = { "name": "A1", "health": 0.521, "children": [{ "name": "B1", "health": 0.521, "children": [{ "name": "B1-C1", "health": 0.614, "children": [{ "name": "B1-C1-D1", "health": 0.666, "children": [{ "name": "B1-C1-D1-E1", "value": 30, "health": 0.8 }, { "name": "B1-C1-D1-E2", "value": 35, "health": 0.5 }, { "name": "B1-C1-D1-E3", "value": 20, "health": 0.7 } ] }, { "name": "B1-C1-D2", "health": 0.45, "children": [{ "name": "B1-C1-D2-E1", "value": 10, "health": 0.8 }, { "name": "B1-C1-D2-E1", "value": 14, "health": 0.1 } ] }, { "name": "B1-C1-D3", "health": 0.64, "children": [{ "name": "B1-C1-D3-E1", "value": 10, "health": 0.8 }, { "name": "B1-C1-D3-E2", "value": 14, "health": 0.2 }, { "name": "B1-C1-D3-E3", "value": 7, "health": 0.7 }, { "name": "B1-C1-D3-E4", "value": 9, "health": 0.9 }, { "name": "B1-C1-D3-E5", "value": 5, "health": 0.6 } ] }, { "name": "B1-C1-D4", "value": 2, "health": 0.7 } ] }, { "name": "B1-C2", "health": 0.45, "children": [{ "name": "B1-C2-D1", "health": 0.45, "value": 12 }] }, { "name": "B1-C3", "health": 0.5, "children": [{ "name": "B1-C3-D1", "health": 0.5, "value": 10 }] } ] }] } const treemapLayout = d3.treemap() .size([500, 300]) .paddingOuter(16); // update the view const update = (d) => { //console.log(d) let rootNode = d3.hierarchy(d) console.log(rootNode) rootNode .sum(function(d) { return d.value; }) .sort(function(a, b) { return b.height - a.height || b.value - a.value; }); treemapLayout(rootNode); let nodes = d3.select('svg g') .selectAll('g') .data(rootNode.descendants()) nodes .exit().remove() nodes = nodes .enter() .filter(function(d) { return d.depth < 3; }) .append('g') .merge(nodes) .attr('transform', function(d) { return 'translate(' + [d.x0, d.y0] + ')' }) //nodes nodes.append('rect') .attr('width', function(d) { return d.x1 - d.x0; }) .attr('height', function(d) { return d.y1 - d.y0; }) .attr('style', function(d) { return ('fill:' + d3.interpolateRdYlGn(d.data.health)) }) .on('click', function(d) { console.log(d.data.name); update(d); }) nodes .append('text') .attr('dx', 4) .attr('dy', 14) .text(function(d) { return d.data.name; }) }; update(data);
<script src="https://d3js.org/d3.v5.min.js"></script> <svg width="500" height="300"> <g></g> </svg>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.