有几种方法可以解决这个问题。您可以轻松地使用进入/更新/退出周期,尽管与典型的周期使用相比,这有点复杂,因为嵌套元素和需要设置键以确保图表状态之间的平滑转换。
在这种情况下,简单地使用数组来保存要过滤掉的条形、隐藏这些条形、更新比例以不使用这些键的值并更新剩余的条形可能更容易。
这需要每个图例项都有一个 onclick 事件。点击时,在我们的 clicked 函数中,我们管理过滤掉的 (filtered) 项数组,如下所示,其中 d 是与图例矩形关联的基准:
// add the clicked key if not included:
if (filtered.indexOf(d) == -1) {
filtered.push(d);
// if all bars are un-checked, reset:
if(filtered.length == keys.length) filtered = [];
}
// otherwise remove it:
else {
filtered.splice(filtered.indexOf(d), 1);
}
然后我们可以更新尺度(对于x1 尺度的域,我们需要所有不在过滤数组中的键,因此需要newKeys 变量):
var newKeys = [];
keys.forEach(function(d) {
if (filtered.indexOf(d) == -1 ) {
newKeys.push(d);
}
})
x1.domain(newKeys).rangeRound([0, x0.bandwidth()]);
y.domain([0, d3.max(data, function(d) { return d3.max(keys, function(key) { if (filtered.indexOf(key) == -1) return d[key]; }); })]).nice();
然后我们可以选择我们的矩形,过滤它们是否应该隐藏或显示,并相应地更新:
var bars = svg.selectAll(".bar").selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
// filter out bars:
bars.filter(function(d) {
return filtered.indexOf(d.key) > -1;
})
.transition()
.attr("x", function(d) {
return (+d3.select(this).attr("x")) + (+d3.select(this).attr("width"))/2;
})
.attr("height",0)
.attr("width",0)
.attr("y", function(d) { return height; })
.duration(500);
// update persistent bars:
bars.filter(function(d) {
return filtered.indexOf(d.key) == -1;
})
.transition()
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x1.bandwidth())
.attr("fill", function(d) { return z(d.key); })
.duration(500);
这个解决方案可以通过进入/更新/退出周期变得更加“d3-ish”,但由于我们的元素数量相对固定,这不像在许多其他情况下那样有用。
这是上面的代码:
https://bl.ocks.org/andrew-reid/64a6c1892d1893009d2b99b8abee75a7
正如 cmets 中所述,您还需要更新轴,而不仅仅是比例。为此,我在 y 刻度中添加了一个类,以便在更新图表时轻松选择:
svg.select(".y")
.transition()
.call(d3.axisLeft(y).ticks(null, "s"))
.duration(500);