d3:DOM元素并没有真正绑定到数据(?)

时间:2013-06-13 08:26:33

标签: d3.js selection

我对此完全感到困惑。我用http://bl.ocks.org/mbostock/raw/3808234/处的字母查看了示例,其中更新的元素根据数据集中字母的位置更改其位置。

现在我想重现类似的东西,但是使用div元素('.item's)。到目前为止,我有:

var displayData = function() {
    // DATA JOIN
    var items = d3.select('#data').selectAll('.item');
    items = items.data(data);
    // UPDATE
    items.transition().duration(500)
        .style('left', function(d, i) {
            return positions[i].left + "px";
        }).style('top', function(d, i) {
            return positions[i].top + "px";
        });

    // ENTER
    var div = items.enter().append('div')
        .attr('class', 'item')
        .style('left', function(d, i) {
            return positions[i].left + "px";
        }).style('top', function(d, i) {
            return positions[i].top + "px";
        })
        .style('opacity', 1e-6)
        .transition().duration(TRANSITION_DURATION)
        .style('opacity', 1);

    // EXIT
    items.exit().transition().duration(500).style('opacity', 0).remove();
}

positions是具有预先计算位置的简单对象数组(它们根据屏幕大小而变化),例如:

positions = 
[{left: 0, top: 0}, 
{left: 240, top: 0}, 
{left: 0, top: 360}, 
{left: 240, top: 360}]

因此,给定一个包含四个数据对象data = [{a},{b},{c},{d}]的数组,上面的代码在第一次调用时会生成div.item的2x2网格。

现在当我将数据更改为data = [{b},{a}]时会发生什么事让我困惑。数据加入后,items如下所示:

[Array[2]
0: div.item
1: div.item
length: 2
parentNode: div#data
__proto__: Array[0]
]

__data__ div.item 0指向对象{b},我认为这是正确的,但是我不能让第一个和第二个元素交换位置,因为它们"忘记"他们的旧职位。

另一种情况:我们说我将原始数据更改为data = [{b},{a},{e}],即我引入了一个新元素{e}。然后我想交换前两个元素(带过渡)并首先删除第三个元素({c})并淡入新的第三个元素({e})。这甚至可能吗?我做错了什么/我误解了什么?

2 个答案:

答案 0 :(得分:1)

我建议您阅读How Selections Work

您的示例与原始示例不同,因为您在绑定数据时未使用键功能。如果未指定键函数,则默认使用元素的位置(索引)来确定哪些元素相同(因此应保留用于更新选择),以及应添加/删除哪些元素。

来自documentation

  

如果未指定键功能,则指定数组中的第一个数据将分配给当前选择中的第一个元素,第二个数据分配给第二个选定元素,依此类推。

因此,我建议使用键功能,以便在绑定新数据时添加,更新和删除正确的元素。

答案 1 :(得分:0)

在阅读了一些问题和示例之后,我发现问题与对象恒定性有关(参见http://bost.ocks.org/mike/constancy/)。我必须在data函数中指定某个键:

items = items.data(data, function(d){ return d.key; );