在转换结束时调用回调
Invoke a callback at the end of a transition
我需要使用 D3 创建一个 FadeOut 方法(类似于 jQuery.js(。我需要做的是使用 transition()
将不透明度设置为 0。
d3.select("#myid").transition().style("opacity", "0");
问题是我需要一个回调来实现转换何时完成。如何实现回调?
你想要侦听转换的"结束"事件。
// d3 v5
d3.select("#myid").transition().style("opacity","0").on("end", myCallback);
// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
- 此演示使用"end"事件按顺序链接多个转换。
- D3 附带的甜甜圈示例也使用它来链接多个过渡。
- 这是我自己的演示,它改变了过渡开始和结束时元素的样式。
来自transition.each([type],listener)
的文档:
有关如果指定了 type,则为转换事件添加侦听器,同时支持"开始"和"结束"事件。将为转换中的每个元素调用侦听器,即使转换具有恒定的延迟和持续时间也是如此。start 事件可用于在每个元素开始转换时触发瞬时更改。结束事件可用于通过选择当前元素、
this
并派生新过渡来启动多阶段转换。在结束事件期间创建的任何转换都将继承当前转换 ID,因此不会覆盖先前计划的较新转换。
更多详细信息,请参阅有关该主题的论坛帖子。
最后,请注意,如果只想在元素淡出后(过渡完成后(删除元素,则可以使用 transition.remove()
。
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") });
现在,在 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();
}
});
从 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
以下是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);
}
。我们可以像这样扩展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");
如果指定了毫秒数或第二个参数为 true,即使transition
为空,d3.transition.end
也会应用传递的callback
。这还会将任何其他参数转发给callback
(并且仅转发这些参数(。重要的是,如果transition
为空,则默认情况下不会应用callback
,在这种情况下,这可能是一个更安全的假设。
Mike Bostock 的解决方案通过 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");
实际上,还有另一种使用计时器的方法可以做到这一点。
var timer = null,
timerFunc = function () {
doSomethingAfterTransitionEnds();
};
transition
.each("end", function() {
clearTimeout(timer);
timer = setTimeout(timerFunc, 100);
});
我通过使用变量设置过渡的持续时间来解决类似的问题。然后我用setTimeout()
调用下一个函数。就我而言,我希望转换和下一次调用之间略有重叠,如您的示例所示:
var transitionDuration = 400;
selectedItems.transition().duration(transitionDuration).style("opacity", .5);
setTimeout(function () {
sortControl.forceSort();
}, (transitionDuration * 0.75));
- 为什么(如何)'这'从函数内部调用回调时发生更改
- 在初始函数完成之前调用回调函数
- Node.js exec调用从不调用回调
- 如何从参数数组中调用回调
- 如何在调用回调之前禁用按钮
- 加载文件,然后调用回调函数
- async.retry-已调用回调
- 节点.js“已调用回调”.但是没有任何其他回调
- JavaScript - 返回承诺和/或调用回调
- 解析查询.首次成功/错误 间歇性不调用回调
- 如何使用另一个 JavaScript 文件中定义的类名调用回调函数
- ReactJs:this.setState的情况下不调用回调函数
- $.post到PHP文件-在包含循环完成之前不会调用回调
- 异步加载ASP.NET绑定的Javascript,然后调用回调
- setTimeout()在其设置时间之前连续调用回调函数
- 在其他回调js中调用回调
- Ajax 调用重新加载页面,而不是调用回调函数
- Angularjs $http.get 不调用回调
- 未调用回调函数
- jQuery JSONP 不调用回调