在转换结束时调用回调

时间:2012-05-21 20:25:12

标签: javascript d3.js transition

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

d3.select("#myid").transition().style("opacity", "0");

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

9 个答案:

答案 0 :(得分:123)

您想要倾听过渡的“结束”事件。

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

// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
  • This demo使用“结束”事件按顺序链接多个转换。
  • D3附带的donut example也使用它将多个过渡链接在一起。
  • 这里是my own demo,可以在转换的开始和结束时更改元素的样式。

来自transition.each([type],listener)的文档:

  

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

有关详细信息,请参阅this forum thread on the topic

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

答案 1 :(得分:63)

Mike Bostock的solution 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") });

答案 2 :(得分:45)

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

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

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

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

答案 3 :(得分:10)

稍微不同的方法,当有许多转换同时运行多个元素时,它们也会起作用:

var transitions = 0;

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

答案 4 :(得分:6)

以下是Mike Bostock solution的另一个版本,灵感来自@ hughes'评论@ kashesandr的回答。它会在undefined结束时进行一次回调。

给定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); }

d3

As a JSFiddle

使用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; }

transition.end(callback[, delayIfEmpty[, arguments...]])

...或transition.end(function() { console.log("all done"); }); 为空时可选延迟:

transition

...或使用可选的transition.end(function() { console.log("all done"); }, 1000); 参数:

callback

transition.end(function(x) { console.log("all done " + x); }, 1000, "with callback arguments"); 将应用已通过的d3.transition.end即使空callback ,如果指定的毫秒数第二个论点是真实的。这也会将任何其他参数转发给transition(只有那些参数)。重要的是,如果callback为空,不会默认应用callback,在这种情况下这可能是更安全的假设。

答案 5 :(得分:2)

从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();

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

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

答案 6 :(得分:0)

迈克博斯托克的solution通过kashesandr +改进了回调函数的参数:

function d3_transition_endall(transition, callback, arguments) {
    if (!callback) callback = function(){};
    if (transition.size() === 0) {
        callback(arguments);
    }

    var n = 0;
    transition
        .each(function() {
            ++n;
        })
        .each("end", function() {
            if (!--n) callback.apply(this, arguments);
    });
}

function callback_function(arguments) {
        console.log("all done");
        console.log(arguments);
}

d3.selectAll("g").transition()
    .call(d3_transition_endall, callback_function, "some arguments");

答案 7 :(得分:-2)

实际上还有一种方法可以使用计时器。

var timer = null,
    timerFunc = function () {
      doSomethingAfterTransitionEnds();
    };

transition
  .each("end", function() {
    clearTimeout(timer);
    timer = setTimeout(timerFunc, 100);
  });

答案 8 :(得分:-2)

我通过使用变量设置转换的持续时间来解决类似的问题。然后我使用setTimeout()来调用下一个函数。在我的情况下,我希望转换和下一个调用之间略有重叠,正如您在我的示例中看到的那样:

var transitionDuration = 400;

selectedItems.transition().duration(transitionDuration).style("opacity", .5);

setTimeout(function () {
  sortControl.forceSort();
}, (transitionDuration * 0.75)); 
相关问题