问题:
我试图了解general update pattern中d3退出选择的行为。
注意:我正在使用d3V5
Fiddle
假设我要可视化数字“ 1”。
var data = [{id:"1"}];
var text = svg.selectAll('.text').data(data);
text.enter()
.each((d) => console.log("first append " + d))
.append('text')
.text(d => d.id)
一切都很好。但现在说我对“ 1”感到厌倦,并且对可视化“ 2”更感兴趣。
data = [{id:"2"}];
text = svg.selectAll('.text').data(data);
text.exit().each((d) => console.log("remove " + d)).remove();
控制台不记录
{id:"1"}
。此项未放置在退出选择中。text.enter()
.each((d) => console.log("now append " + d))
.append('text')
.text(d => d.id)
现在我有一个“ 1”和一个“ 2”彼此堆叠。
假设:
我曾以为,当我执行
.data(data)
时,d3会在dom和数据之间进行区分,并将所有没有相应条目的旧dom节点放置在退出选择的data
中。我以为数据上的'id'
字段可以区分这些数据元素。事实并非如此。题:
如何在退出选择中得到
{id:"1"}
?或者如何删除与
{id:"1"}
关联的dom节点? 最佳答案
这里的混乱始于错误的假设。在我所见过的大多数d3示例中,数据具有以下格式:
[ {'id': 1, 'info': 'something'}, {'id': 2, 'info': 'something else'}, ...]
我一直以为默认情况下,selection.data()使用数据的
'id'
字段执行了比较。事实证明并非如此,您需要提供自己的键功能。
从D3's selection docs:
如果未指定键功能,则将数据中的第一个数据分配给第一个选定元素,将第二个数据分配给第二个选定元素,依此类推。
所以我添加了一个关键功能:
function idFunc(d) { return d ? d.id : this.id; }
var data = [{id:"1"}];
var text = svg.selectAll('text').data(data, idFunc);
text.enter()
.append('text')
.text(d => d.id)
然后,不再与数据数组中的项目相对应的dom节点找到了进入出口选择的方式,并且我能够将其删除。
结论:
(始终)在您
.data(data, keyFunc)
时在数据上定义键功能