Javascript D3.enter().merge()不工作

Javascript D3.enter().merge()不工作,javascript,d3.js,Javascript,D3.js,我正在努力使V4中的通用更新模式正常工作,尽管我相信我通过merge()了解它的新工作方式。我遇到了奇怪的结果。以下是我的更新功能: function update(data) { //I create and empty selection, and use the key function with an ID string //in my dsv data. var bubs = dataLr.selectAll(".data-bub") .dat

我正在努力使V4中的通用更新模式正常工作,尽管我相信我通过
merge()
了解它的新工作方式。我遇到了奇怪的结果。以下是我的更新功能:

function update(data) {

    //I create and empty selection, and use the key function with an ID string
    //in my dsv data.
    var bubs = dataLr.selectAll(".data-bub")
        .data(data, function(d) {
            return d.id || (d.id = ++i);
        });

    //remove any that dont need to be there.
    //The first time around there wont be any nodes in the exit, but no matter.
    bubs.exit()
        .transition(tIntro)
        .style("opacity", 0)
        .each(function(d) {
            //Log out the removed elements.
            console.log(d.id);
        })
        .remove();

    bubs.enter() //add any new ones - a group and a circle within it.
        .append("g")
        .classed("data-bub", true)
        .on("click", function(d) {
            console.log(d);
        })
        .append("circle")
        .attr("r", 20)
        .classed("bub", true)
        .merge(bubs);//here I merge the enter with the update.


    //Now I should be able to run this transition that 
    //moves each group to a random location on my svg.
    //But nothing happens. Why is the update selection empty after merge?
    bubs.transition(tIntro)
        .attr("transform", function(d, i) {
            ///console.log(i);
            var y = Math.random() * gHeight;
            var x = Math.random() * gWidth;
            return "translate(" + x + "," + y + ")";
        });

}
此外,另一件可怕的事情不断发生。目前,我正在运行此功能,而不更改数据。因此,在
exit()
enter()
上不应删除任何元素。但是每次都会删除并重新添加两个随机的?什么鬼东西?

.merge()
不会更改选择-在d3v4中,选择是不可变的。因此,一旦声明,选择将始终保持不变,除非重新定义它。如果初始的
selectAll
方法返回一个空选择,
bubs
在udpate选择中不会有任何内容-直到您重新定义
bubs
。合并所做的一切是:

返回一个新的选择,将此选择与指定的 其他选择。()

如果只是添加
g
元素,那么可以使用:

bubs.enter() 
    .append("g")
    .merge(bubs)
    // apply transition to enter and update selection
    .transition()...
或者,使用merge返回的选择重新定义
bubs

bubs = bubs.enter() 
    .append("g")
    .merge(bubs);

// apply transition to enter and update selection
bubs.transition()....
但是您的代码会遇到问题,因为您有两种不同类型的元素选择:初始选择的
selectAll(“.data bub”)
——根据您的代码选择
g
元素,以及选择输入的圆:

bubs.enter()         
    .append("g")               // return entered g elements
    .classed("data-bub", true) // return entered g elements with class data-bub
    .append("circle")          // return entered circles
    .merge(bubs);              // return entered circles with initially selected g elements
如果将转换应用到合并元素,则转换将不均匀地应用到父
g
元素(在更新的情况下)和子
元素(在输入的情况下)。这可能会导致不期望的结果(例如,如果您还有子文本元素)。要解决此问题(并对输入和更新的
g
元素应用转换),您可以尝试以下方法:

    var bubs = dataLr.selectAll(".data-bub")
        .data(data, function(d) { return d.id || (d.id = ++i); });

    // remove as before
    bubs.exit()
       .remove();

   // enter new groups
   var enter = bubs.enter()  
      .append("g")
      .classed("data-bub", true);

   // append circles to the new groups
   enter.append("circle")
        .attr("r", 20)
        .classed("bub", true)

   // merge enter and update, apply transition
   enter.merge(bubs)
      .transition()....

我尝试了你的第一个建议,但是这个转变被应用到了圈子里,而不是更大的群体,导致了疯狂。我试试看。谢谢。是的,很抱歉,我错过了您使用“合并”时选择的是
circle
s元素,而不是
g
元素,我已更新以确认这一点。v2已经过时,并且缺少文档,如果可能的话,我会尽量避免它。这是可行的。将每个选择添加到变量实际上让我明白了每个选择都是不可变的。但我的第二个问题仍然存在。每次运行此更新函数时,都会添加和删除两个元素,尽管输入数据没有更改。所有应该发生的事情就是转换到现有元素的新位置。如果删除.data()中的键控函数,它还会继续这样做吗?对于未定义id的基准,
i
可能会递增-在没有看到数据的情况下,我可能会说数据数组中的两个元素没有id。(这并不像我想的那么清楚:如果每次使用时都没有重置
i
。.data(),则每次运行更新功能时,键都将不同,并且项目将被删除和输入,假设未在每个数据中定义d.id),使用
。数据(数据)
应能够确认键是否存在问题。