Answers:
您想收听过渡的“结束”事件。
// d3 v5
d3.select("#myid").transition().style("opacity","0").on("end", myCallback);
// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
从文档中transition.each([type],listener)
:
如果指定了type,则为过渡事件添加一个侦听器,同时支持“开始”和“结束”事件。即使过渡具有恒定的延迟和持续时间,也会为过渡中的每个单独元素调用侦听器。当每个元素开始转换时,开始事件可用于触发瞬时更改。通过选择当前元素
this
,并派生新的过渡,可以将结束事件用于启动多阶段过渡。在结束事件期间创建的任何过渡都将继承当前的过渡ID,因此不会覆盖以前计划的较新过渡。
有关更多详细信息,请参见主题上的此论坛主题。
最后,请注意,如果您只想在元素淡出后(过渡完成后)将其删除,则可以使用transition.remove()
。
d3.selectAll()
之后(而不是在每个元素完成之后)如何执行回调?换句话说,我只想在所有元素完成转换后回调一个函数。
.each
事件侦听器或"end"
事件的Observable笔记本。它似乎并没有“链接”过渡。第二个链接指向一个不为我加载的github。
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") });
if (transition.size() === 0) { callback(); }
function endall(transition, callback){ if(!callback) return; // ... }
或者,因为从根本上来说,没有回调而调用此函数是一个错误,因此抛出异常是处理情况的适当方法,我认为此案不需要太复杂的例外 function endall(transition, callback){ if(!callback) throw "Missing callback argument!"; // .. }
enter()
和exit()
过渡,并要等到所有的三个已经完成,我们需要把代码中的回调,以确保它被调用三次,对吗?D3太乱了!我希望我选择了另一个图书馆。
现在,在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 解决方案的另一个版本,其灵感来自@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;
}
用途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
如果指定了毫秒数或第二个参数为true,则callback
即使空值也将应用传递的内容。这还将把所有其他参数转发给(并且仅这些参数)。重要的是,默认情况下这不会应用if 为空,在这种情况下,这可能是一个更安全的假设。transition
callback
callback
transition
从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();
有关更多信息,请参见版本发行说明:
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");