20

据我了解,更新 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) 那么错误的圆圈会用新数据更新。

有什么办法吗?

4

1 回答 1

57

这是key 函数的目的,它是selection.data的第二个参数:它允许您通过控制哪个数据绑定到哪个元素来保持对象的恒定性。例如,假设您有一个代表水果的对象数组:

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

当您第一次创建元素时,您不需要 key 函数,因为没有任何现有元素,因此您可以使用标准 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();

这称为一般更新模式。(你可以在第一次这样做;它是 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与 data 匹配fruit2,但 DOM 中的顺序不匹配,因为输入元素被附加到正文的末尾。(selection.append 没有任何花哨的逻辑来保证顺序;它只是将新元素附加到父元素的末尾。)使用 SVG 时,我们通常不关心 DOM 元素的顺序,因为所有内容都是绝对定位的。如果您确实关心订单,则可以在输入后使用selection.order修复它:

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

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

于 2013-06-29T05:41:44.607 回答