2013-06-29 62 views
15

根据我的理解,更新d3数据的正确方法是将其传递到选择的.data()在D3数据中保留订单

我获得的数据没有排序,或者与此相关。所以我非常需要使用更新/添加/删除逻辑。所以在d3中.data().enter().exit()(对吧?)。

所以我想要做的是使用一个JavaScript字典,而不是一个数组,其中的关键是我的唯一标识符。但我似乎无法做到这一点。一个假例如:

data_one[0] = 'Dogs'; 
data_one[1] = 'Cats'; 

d3.selectAll('circle').data(data_one).enter().attr(...) 

我第二次运行此我的数据可能是相同的,但在不同的顺序。我想用与以前相同的属性来表示它。我不想复制我的代码,但是如果我只是执行.data(data_two),那么错误的圈子将更新新数据。

任何方法?

回答

49

这是键功能,第二个参数selection.data的目的:它可以让你通过控制数据被绑定到哪个元素保持object constancy。例如,假设你有对象的数组代表水果:

var fruits = [ 
    {name: "orange", value: 200}, 
    {name: "apple", value: 124}, 
    {name: "banana", value: 32} 
]; 

当你第一次创建的元素,你并不需要的关键功能,因为没有任何现有的元素,所以你可以使用标准的全选,数据输入,追加模式:

var div = d3.select("body").selectAll(".fruit") 
    .data(fruits) 
    .enter().append("div") 
    .attr("class", "fruit") 
    .text(function(d) { return d.name + ": " + d.value; }); 

这种操作的结果是:

<body> 
    <div class="fruit">orange: 200</div> 
    <div class="fruit">apple: 124</div> 
    <div class="fruit">banana: 32</div> 
</body> 

但是,现在让我们假设你的数据的变化,并且要更新到refle新数据。这一新数据可能会以不同的顺序,并且一些元素可以添加或删除:

var fruits2 = [ 
    {name: "apple", value: 124}, 
    {name: "lemon", value: 17}, 
    {name: "banana", value: 32}, 
    {name: "strawberry", value: 1465} 
]; 

苹果和香蕉分别在原始数据,所以我们想留住他们。这被称为更新选择。草莓和柠檬是新的;这是输入的选择。最后橘子走开了,形成了退出的选择。

使用引用数据的name属性的键函数,我们可以按照预期将新数据分配给旧元素。然后,我们可以创建进入水果和删除退出的水果:

var div = d3.select("body").selectAll(".fruit") 
    .data(fruits2, function(d) { return d.name; }); 

div.enter().append("div") 
    .attr("class", "fruit") 
    .text(function(d) { return d.name + ": " + d.value; }); 

div.exit().remove(); 

这就是所谓的general update pattern。 (你可有周围做这个的第一次;它的全选,数据输入,追加模式的更一般的形式)的结果是:

<body> 
    <div class="fruit">apple: 124</div> 
    <div class="fruit">banana: 32</div> 
    <div class="fruit">lemon: 17</div> 
    <div class="fruit">strawberry: 1465</div> 
</body> 

虽然选择div顺序的数据相匹配fruit2 ,DOM中的顺序不是而是,因为输入元素被添加到主体的末尾。 (选择。追加没有任何花哨的逻辑来保证排序;它只是将新元素添加到父项的最后)。使用SVG时,我们通常不关心DOM元素的顺序,因为所有元素都是绝对定位的。如果您做一下顺序护理,你可以使用selection.order进入后修复:

div.order(); // make the DOM element order match the selection 

而且,在这个例子中,我们不需要做出更新选择的任何变化,因为这些值对于苹果和香蕉没有改变。如果更新数据也发生变化,您可以直接调用selection.attr和selection.text来调用上面的selection.data调用。

+1

谢谢迈克!!!! – ehsan

+0

THx的答案。我在两个准相同的情况下使用selection.order(),一次它工作,一次它不。选择的顺序究竟是什么?它取决于给数据功能的关键吗? – JulienFr

+0

我想答案是基于“[enter.append有一个方便的副作用:它用更新选择中的新元素替换了输入选择中新创建的元素。因此,在enter.append之后,更新选择是修改为包含输入和更新元素。](https://bost.ocks.org/mike/selection/#enter-update)“。但是,我的[测试](https://gist.github.com/an0/a924bf0d25e43d71584402dff6e28344)似乎并非如此。更新选择仍然只包含enter.append后的更新。必须在'update'和'enter'的'merge'上调用'order'使其工作。为什么? – an0