回答:
トランジションの「終了」イベントをリッスンしたい。
// 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)
:
タイプが指定されている場合、遷移イベントのリスナーを追加し、「開始」イベントと「終了」イベントの両方をサポートします。トランジションに一定の遅延と期間がある場合でも、リスナーはトランジション内の個々の要素ごとに呼び出されます。開始イベントを使用して、各要素が遷移を開始するときに瞬間的な変更をトリガーできます。終了イベントを使用して、現在の要素を選択し
this
、新しい遷移を導出することにより、多段階遷移を開始できます。終了イベント中に作成された遷移は、現在の遷移IDを継承するため、以前にスケジュールされた新しい遷移を上書きしません。
詳細については、このトピックに関するこのフォーラムのスレッドを参照してください。
最後に、要素がフェードアウトした後(遷移が終了した後)に要素を削除したいだけの場合は、を使用できることに注意してくださいtransition.remove()
。
d3.selectAll()
(各要素が終了した後ではなく)終了した後にのみ、どのようにコールバックを実行しますか?つまり、すべての要素の遷移が完了したら、1つの関数をコールバックするだけです。
.each
イベントリスナーもイベントも使用しないObservableノートブックを指しています"end"
。遷移を「連鎖」させていないようです。2番目のリンクは、ロードされないgithubを指しています。
マイクボストックの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()
遷移を、3つすべてが完了するまで待ちたい、我々は確かにそれは右、3回呼び出されています作るために、コールバックにコードを配置する必要がありますか?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();
}
});
以下は、マイクボストックのソリューションの別のバージョンであり、@ kashesandrの回答に対する@hughesのコメントに触発されました。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
ミリ秒数が指定されている場合、または 2番目の引数が真である場合、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();
詳細については、バージョンのリリースノートを参照してください。
kashesandr +コールバック関数に引数を渡すことで改善されたMike Bostockのソリューション:
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");
変数を使用して遷移に期間を設定することで、同様の問題を解決しました。次にsetTimeout()
、次の関数を呼び出すために使用しました。私の例では、私の例でわかるように、遷移と次の呼び出しの間にわずかなオーバーラップが必要でした。
var transitionDuration = 400;
selectedItems.transition().duration(transitionDuration).style("opacity", .5);
setTimeout(function () {
sortControl.forceSort();
}, (transitionDuration * 0.75));