保持D3数据的顺序

时间:2013-06-29 04:12:28

标签: d3.js

根据我的理解,更新d3数据的正确方法是将其传递到选择的.data()

我获得的数据不是有序的,也不是一致的。所以我非常需要使用更新/添加/删除逻辑。所以d3术语是.data() .enter().exit()(对吧?)。

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

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

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

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

有什么方法吗?

1 个答案:

答案 0 :(得分:53)

这是键函数的目的,是selection.data的第二个参数:它允许您通过控制哪个数据绑定到哪个元素来维护object constancy。例如,假设您有一组表示水果的对象:

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

首次创建元素时,您不需要键功能,因为没有任何现有元素,因此您可以使用标准的selectAll-data-enter-append模式:

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>

但现在让我们说您的数据发生了变化,并且您希望更新以反映新数据。这些新数据的顺序可能不同,可能会添加或删除一些元素:

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。 (你可以在第一次这样做;它是selectAll-data-enter-append模式的更一般形式。)结果是:

<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中的顺序,因为输入的元素已附加到正文的末尾。 (selection.append没有任何花哨的逻辑来保证排序;它只是将新元素附加到父元素的末尾。)当使用SVG时,我们通常不关心DOM元素的顺序,因为所有内容都是绝对定位的。如果您 关心订单,可以在输入后使用selection.order进行修复:

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

此外,在此示例中,我们不需要对更新选择进行任何更改,因为apple和banana的值没有更改。如果更新数据也发生变化,您可以直接从上面的selection.data调用中对selection.attr和selection.text进行链式调用。