我想更新单个数据点并仅修改它绑定的元素,但我无法弄清楚如何执行此操作。
This article似乎表明var sel = svg.selectAll(...).data(...)
提供了一系列更新数据,然后sel.enter(...)
代表新数据,之后sel
同时代表更新的+新数据。
在this jsfiddle example中,我将新元素作为绿色和更新的元素着色为蓝色,但似乎每个现有元素都被着色为蓝色,而不仅仅是自从最后更新。如何更新单个数据?
// ...
function update() {
// clear old classes
svg.selectAll("text").attr("class","");
// join to the new data
var sel = svg.selectAll("text").data(things);
// update -- but this actually affects all elements in the selection?
sel.attr("class","update");
// enter
sel.enter()
.append("text")
.attr("class","enter")
.attr("x", function(d,i) { return 20*i; })
.attr("y", 20);
// update + enter
sel.text(function(d) { return d; });
// exit
sel.exit().remove();
}
答案 0 :(得分:1)
正如您所发现的,“更新”选项包括所有现有元素,无论数据是否实际更改,都可以随时更新。
如果要测试新数据是否与旧数据相同或不同,则需要一种方法来保留旧数据以与新数据进行比较。然后,您可以使用选择过滤器来丢弃数据相同的元素。
我已经讨论过这个问题previously on the d3 mailing list。这是我提出的方法:
selection = selection.property(" __oldData__", function(d){ return d; } );
//store the old data as a property of the node
.data(newData);
//over-write the default data property with new data
selection.enter() /*etc*/; //handle new elements
selection.filter( function(d) {
//test whether the relevant properties of d match the equivalent in the oldData
//also test whether the old data exists, to catch the entering elements!
return ( (this.__oldData__ ) &&
(d.value != this.__oldData__.value) );
})
.style("fill", "blue");
selection.property("__oldData__", null);
//delete the old data once it's no longer needed
你当然可以使用旧数据属性的任何名称,只是在它周围抛出很多“_”字符以避免弄乱任何浏览器的本机DOM属性。之后您不需要删除oldData(下次更新时它将被覆盖),但如果您不经常更新,它可以节省内存以显式释放它。
请注意selection.filter()
不保留索引值。如果你需要跟踪i
,你可以添加一个额外的步骤来保存索引,然后作为单独的属性(元素或数据对象)进行过滤,或者你可以跳过过滤器而只是做测试直接在style / attr调用中的函数中。
编辑:相对于链接的讨论,我更改了过滤器功能,因此仅包含更新的元素,而不是新的或更新的元素。无论哪种方式,过滤器都会选择过滤函数返回true的元素。
答案 1 :(得分:0)
在你的情况下,搞清楚这一点相对容易。您要将元素的文本设置为数据,因此您需要做的就是在决定数据是否已更新时进行比较:
sel.classed("update", function(d) { return d != d3.select(this).text(); });
完整演示here。有关一般解决方案,请参阅AmeliaBR的回答。