在转换结束时调用callback

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

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

问题是我需要一个callback来实现转换完成。 我怎样才能实现callback?

您想要听取转换的“结束”事件。

 d3.select("#myid").transition().style("opacity","0").each("end", myCallback); 
  • 该演示使用“结束”事件按顺序链接许多转换。
  • 与D3一起发运的甜甜圈例子也使用它来链接多个转换。
  • 这是我自己的演示 ,它改变了转换开始和结束时元素的风格。

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

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

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

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

Mike Bostock针对v3的解决scheme进行了小小的更新:

  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") }); 

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

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

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

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

稍微不同的方法也适用于有许多元素同时运行的许多转换:

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

以下是Mike Bostock 解决scheme的另一个版本,并受@hughes对@ kashesandr的回答的评论的启发。 它在transition结束时做出一个callback。

给定一个dropfunction…

 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

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

作为JSFiddle 。

使用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"); 

如果指定了毫秒数, 或者第二个参数是truthy,则d3.transition.end即使在空transition 也会应用传递的callback 。 这也将转发任何​​额外的参数callback (只有那些参数)。 重要的是,如果transition为空,这不会默认应用callback ,在这种情况下这可能是一个更安全的假设。

Mike Bostock的解决scheme通过将kashesandr +parameter passing给callback函数进行了改进:

 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"); 

实际上还有一种方法可以使用定时器来实现这一点。

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

我通过使用variables设置转换持续时间来解决类似的问题。 然后我使用setTimeout()来调用下一个函数。 在我的例子中,我想在转换和下一个调用之间稍微重叠,就像我在例子中看到的那样:

 var transitionDuration = 400; selectedItems.transition().duration(transitionDuration).style("opacity", .5); setTimeout(function () { sortControl.forceSort(); }, (transitionDuration * 0.75));