在转换结束时调用回调

Ton*_*ony 95 javascript transition d3.js

我需要使用D3.js制作一个FadeOut方法(类似于jQuery).我需要做的是使用不透明度设置为0 transition().

d3.select("#myid").transition().style("opacity", "0");
Run Code Online (Sandbox Code Playgroud)

问题是我需要一个回调来实现转换完成的时间.我该如何实现回调?

Phr*_*ogz 132

您想要倾听过渡的"结束"事件.

// d3 v5
d3.select("#myid").transition().style("opacity","0").on("end", myCallback);

// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
Run Code Online (Sandbox Code Playgroud)
  • 该演示使用"结束"事件按顺序链接许多转换.
  • D3附带的甜甜圈示例也使用它将多个过渡链接在一起.
  • 这是我自己的演示,它在转换的开始和结束时改变元素的样式.

从以下文档transition.each([type],listener):

如果指定了type,则为转换事件添加侦听器,同时支持"start"和"end"事件.即使转换具有恒定的延迟和持续时间,也将为转换中的每个单独元素调用侦听器.启动事件可用于在每个元素开始转换时触发瞬时更改.结束事件可用于通过选择当前元素this和导出新转换来启动多阶段转换.在结束事件期间创建的任何转换都将继承当前转换ID,因此不会覆盖先前计划的较新转换.

有关更多详细信息,请参阅此主题的论坛主题.

最后,请注意,如果您只想在淡出后删除元素(在转换完成后),您可以使用transition.remove().

  • 所以,我从转换结束后继续这种方式的问题是它运行你的函数N次(对于转换元素集中的N个项).这有时远非理想. (8认同)
  • 非常感谢你.这是一个伟大的图书馆,但在文档中找到重要信息并不容易. (7认同)
  • 没关系.我找到了它:https://gist.github.com/miguelmota/3faa2a2954f5249f61d9 (5认同)
  • 我有同样的问题。希望它在最后一次删除后运行一次该功能 (2认同)

kas*_*ndr 65

Mike Bostock 针对v3解决方案,提供了一个小更新:

  function endall(transition, callback) { 
    if (typeof callback !== "function") throw new Error("Wrong callback in endall");
    if (transition.size() === 0) { callback() }
    var n = 0; 
    transition 
        .each(function() { ++n; }) 
        .each("end", function() { if (!--n) callback.apply(this, arguments); }); 
  } 

  d3.selectAll("g").transition().call(endall, function() { console.log("all done") });
Run Code Online (Sandbox Code Playgroud)

  • 如果选择包含零元素,则回调将永远不会触发.解决这个问题的一种方法是`if(transition.size()=== 0){callback(); }` (5认同)

eri*_*oco 44

现在,在d3 v4.0中,有一个工具可以显式地将事件处理程序附加到转换:

https://github.com/d3/d3-transition#transition_on

要在转换完成后执行代码,您只需要:

d3.select("#myid").transition().style("opacity", "0").on("end", myCallback);
Run Code Online (Sandbox Code Playgroud)

  • 看起来这被称为应用转换的PER元素,这不是我理解的问题. (9认同)

Jes*_* We 10

稍有不同的方法,当有许多转换时,每个转换同时运行多个元素:

var transitions = 0;

d3.select("#myid").transition().style("opacity","0").each( "start", function() {
        transitions++;
    }).each( "end", function() {
        if( --transitions === 0 ) {
            callbackWhenAllIsDone();
        }
    });
Run Code Online (Sandbox Code Playgroud)


mil*_*los 6

以下是Mike Bostock 解决方案的另一个版本,其灵感来自@hughes对@kashesandr的回答.它在transition结束时进行一次回调.

鉴于drop功能......

function drop(n, args, callback) {
    for (var i = 0; i < args.length - n; ++i) args[i] = args[i + n];
    args.length = args.length - n;
    callback.apply(this, args);
}
Run Code Online (Sandbox Code Playgroud)

......我们可以这样延伸d3:

d3.transition.prototype.end = function(callback, delayIfEmpty) {
    var f = callback, 
        delay = delayIfEmpty,
        transition = this;

    drop(2, arguments, function() {
        var args = arguments;
        if (!transition.size() && (delay || delay === 0)) { // if empty
            d3.timer(function() {
                f.apply(transition, args);
                return true;
            }, typeof(delay) === "number" ? delay : 0);
        } else {                                            // else Mike Bostock's routine
            var n = 0; 
            transition.each(function() { ++n; }) 
                .each("end", function() { 
                    if (!--n) f.apply(transition, args); 
                });
        }
    });

    return transition;
}
Run Code Online (Sandbox Code Playgroud)

作为JSFiddle.

用途transition.end(callback[, delayIfEmpty[, arguments...]]):

transition.end(function() {
    console.log("all done");
});
Run Code Online (Sandbox Code Playgroud)

...或者如果transition为空则带有可选的延迟:

transition.end(function() {
    console.log("all done");
}, 1000);
Run Code Online (Sandbox Code Playgroud)

...或使用可选callback参数:

transition.end(function(x) {
    console.log("all done " + x);
}, 1000, "with callback arguments");
Run Code Online (Sandbox Code Playgroud)

d3.transition.end如果指定了毫秒数或者第二个参数是真实的,则将应用传递的callback偶数为空.这也将转发任何​​其他参数(并且只有那些参数).重要的是,这不会默认应用if 为空,这在这种情况下可能是更安全的假设.transition callbackcallbacktransition


chr*_*arx 5

从 D3 v5.8.0+ 开始,现在有一种使用transition.end. 文档在这里:

https://github.com/d3/d3-transition#transition_end

Bostock 的一个工作示例如下:

https://observablehq.com/@d3/transition-end

基本思想是,仅通过附加.end(),过渡将返回一个承诺,直到所有元素都完成过渡后才会解决:

 await d3.selectAll("circle").transition()
      .duration(1000)
      .ease(d3.easeBounce)
      .attr("fill", "yellow")
      .attr("cx", r)
    .end();
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅版本发行说明:

https://github.com/d3/d3/releases/tag/v5.8.0