9

我正在使用 D3.js。我的过渡效果很好,但我只有一个问题:如果第二个过渡在第一个结束之前开始,

这是一个演示问题的 JSFiddle:http: //jsfiddle.net/kqxhj/11/

它在大多数情况下都可以正常工作——CDG 和 LAX 会随着数据的变化而被添加和删除——但是如果你快速连续单击按钮两次,你会注意到新元素不会出现。

这是我的代码的核心:

function update(data) { 

  var g = vis.selectAll("g.airport").data(data, function(d) { 
    return d.name;  
  });
  var gEnter = g.enter().append("g")
  .attr("class", function(d) {    
    return "airport " + d.name;
  });
  // Perform various updates and transitions... 
  [...]

  // Remove exited elements. 
  g.exit().transition()
    .duration(1000)
   .attr("transform", "translate(0," + 1.5*h + ")");
  g.exit().transition().delay(1000)
   .remove();
}

d3.select('#clickme').on("click", function() {  
  update(current_data); 
});

我试图添加一些调试语句来弄清楚发生了什么,但我只能看到,当它发生时,退出选择有 4 个元素,而不是 3 个 - 我不明白为什么会这样。

有没有办法,无论是在 D3 还是在基本的 JavaScript 中,我都可以确保转换不会重叠?

4

3 回答 3

12

更新:从 D3 的 3.5 版(2014 年 10 月)开始,可以通过使用命名转换对元素执行并发转换。您只需为每个转换添加不同的名称。

于 2015-05-22T07:51:48.493 回答
8

发生的事情是数据表示在从 DOM 中删除之前“重新输入”(因为您的 remove() 调用链接在转换上)。但是,如果数据表示尚未从 DOM 中删除,则 enter() 选择将不包含该数据,因为它已经存在!然而,您的转换将继续执行,您的数据表示将消失而没有机会“重新输入”。

您需要做的是给现有元素某种标识符。例如:

g.exit().classed('exiting', true);

然后,当您更新您的选择时,如果一个元素“重新进入”,取消退出的过渡并将其恢复到原来的状态:

g.filter('.exiting')
    .classed('exiting', false)
    .transition() // new transition cancels the old one so that remove() isn't called
        .attr('foo', 'bar'); // return to original state

我已经调整了你的小提琴来演示解决方案:http: //jsfiddle.net/hX5Tp/

这是一个精简的小提琴,可以清楚地展示问题(和解决方案):http: //jsfiddle.net/xbfSU/

于 2013-10-29T21:03:59.923 回答
5

在 D3 中,较新的转换总是会中断并覆盖较旧的转换。您可以通过在您的选择中使用 each() 方法来解决您的设计问题。例如

d3.select('.animated')
.transition()
.duration(1000)
.attr({
    ... // Change something
})
.each('end', function () {
    d3.select(this)
    .attr({
        ... // Change something else, after previous transition
    });
});
于 2013-05-02T13:44:12.627 回答