问题描述
我有一个D3 v5树图,我通过过滤器显示了层次结构的三个级别.同时显示所有级别会使地图太忙.我想使用向下钻取或向上钻取功能,以便当您单击给定的rect(子级或父级)时,将该rect重置为根节点,然后从该新项显示层次结构的另外三个层次根节点.
I have a D3 v5 treemap that I show three levels of the hierarchy via a filter. 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.
我认为我正在获取新的根节点数据,但似乎无法通过 onclick
( exit中的console.log().remove()
不会在onclick之后被调用.看来元素没有正确退出,或者没有到达 exit().remove()
.
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). It seems like elements are not exiting correctly, or not getting to the exit().remove()
.
这是代码:
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选择不可变.
执行此操作时...
nodes.enter()
.filter(function(d) {
return d.depth < 3;
})
.append('g')
.merge(nodes)
//etc...
... merge
并没有更改 nodes
是什么,这只是更新选择.
... the merge
is not changing what nodes
is, which is just the update selection.
您必须重新分配它:
nodes = nodes.enter()
//etc...
这是您所做的更改(在较小的SVG中)的代码:
Here is your code with that change (in a smaller 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>
这篇关于在树形图中输入,更新和退出选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!