Javascript 在d3中使用退出转换保持元素顺序(selection.order)

Javascript 在d3中使用退出转换保持元素顺序(selection.order),javascript,d3.js,Javascript,D3.js,我将用小提琴切入主题:[单击第二个按钮快速查看效果] 我使用的是selection.order,因为我需要DOM元素以与数据元素相同的顺序存在 我想向我的.exit()选择添加一个转换。但是,当与.order()结合使用时,该过程会崩溃。要删除的项位于DOM元素列表的开头 我的猜测是:可能是因为order试图获取数据数组中元素的索引——当然它已经不存在了,因此获取-1作为索引,这意味着它应该被排序到DOM元素列表的开头 如果我不使用order,那么退出转换工作得很好:但是如果我在数据数组的一部

我将用小提琴切入主题:[单击第二个按钮快速查看效果]


我使用的是
selection.order
,因为我需要DOM元素以与数据元素相同的顺序存在

我想向我的
.exit()
选择添加一个转换。但是,当与
.order()
结合使用时,该过程会崩溃。要删除的项位于DOM元素列表的开头

我的猜测是:可能是因为
order
试图获取数据数组中元素的索引——当然它已经不存在了,因此获取
-1
作为索引,这意味着它应该被排序到DOM元素列表的开头

如果我不使用order,那么退出转换工作得很好:但是如果我在数据数组的一部分插入了一些东西,那么新的DOM元素当然只是附加到末尾


非常感谢任何提示或帮助

也许您可以尝试仅在插入项目时运行selection.order,而不是在删除项目时运行

因此,要纠正这个错误,您需要在方法doD3()中添加一个参数,该参数包含true/false,以确定是否运行selection.order。因此,在插入项时传递true以保持顺序,在删除项时传递false

参见小提琴:


我相信我有一个解决办法。问题是d3最终排序的不仅仅是你选择的元素。退出的元素不再是您选择的一部分,d3会无意中移动它们。我修改了现有的d3 order函数,以便它接受一个键函数并跳过当前选择中没有的任何内容。这样,退出的元素就保持不变。我的版本需要一个键来检查元素是否在当前选择中。不确定是否有更好的方法来处理这个问题

函数严格顺序(fnKey){
fnKey=fnKey | |函数(d){返回d;};
返回函数(){
对于(var j=-1,m=this.length;++j=0;){
节点=组[i];
如果(!node)继续;
if(next&&next!==node.nextSibling&(!node.nextSibling | | | | seen.has)(fnKey(node.nextSibling.uuuu data_uu))){
next.parentNode.insertBefore(节点,下一个);
}
seen.add(fnKey(node.__数据__));
下一个=节点;
}
}
归还这个;
};
}

在这里查看您的分叉小提琴:

很有趣,但这当然意味着我不能同时更新+删除或插入+删除。而且,我不能在删除转换运行时删除、插入或更新。不确定我是否正确理解了问题。无论是否选择
selection.order()
,我都会得到相同的订单。默认情况下,DOM元素将按照与数据元素相同的顺序追加,您无需执行任何操作即可获得。Lars-它们总是追加的,从不插入。在数据中的索引3处插入一个项将导致它被追加到DOM元素列表的末尾
order()
解决了这个问题,但是在选择
exit()
的情况下,它总是将与删除的数据相关的元素排序到DOM列表的最开始。仍然不能真正理解您的目标。也许你脑子里有一个更复杂的例子来说明这一点?小提琴应该会显示出来——一个简单的DOM元素列表,我希望它们保持其底层数据的顺序。我想设置从该列表中删除项目的动画。同时,插入的项目应显示在其插入的位置。如果这有道理的话?啊,我现在明白你的意思了——我错过了插入位。你基本上看到了这一点,因为你正在使用一个转换。您需要做的是在删除转换完成后进行排序。这在使用
.each(“end”,…)
处理程序时相对容易。问题是,当退出选择为空时,您还需要运行此操作,这需要单独检查。
var items = ['apple', 'banana', 'orange', 'aardvark'];

function doD3(order) {
    var selection = d3.select('div.c')
        .selectAll('p')
    .data(items, function(d) { return d; });

    selection
        .enter()
        .append('p')
    .text(function(d) { return d; })
        .style('opacity', 0)
        .transition()
        .style('opacity', 1);

    selection
        .exit()
        .transition()
        .style('opacity', 0)
        .remove();

    if(order) {
        // remove this to see alternative behaviour
        selection
            .order();    
    }    
}

doD3(true);

$('#b1').click(function() {
    items.splice(1, 0, ['kiwi']);
    doD3(true);
});

$('#b2').click(function() {
    items.splice(2, 1);
    doD3(false);
});