답변:
전환의 "종료"이벤트를 수신하려고합니다.
// 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()
무엇입니까 (대신 각 요소가 완료된 후)? 즉, 모든 요소가 전환을 마치면 하나의 함수 만 콜백하고 싶습니다.
.each
이벤트 리스너 나 이벤트를 사용하지 않는 Observable 노트북을 가리 킵니다 "end"
. 전환을 "연결"하지 않는 것 같습니다. 두 번째 링크는 나를 위해로드되지 않는 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; // ... }
는 콜백없이이 함수를 호출하면 오류가 가장 certanly 때문에, 또는에 예외 솔기를 던지고, 상황을 처리하는 적절한 방법이 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 솔루션 의 또 다른 버전이며 @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
밀리 초 수가 지정 되거나 두 번째 인수가 진실 인 경우callback
비어있는 transition
경우 에도 전달 된 값을 적용합니다 . 또한 추가 인수를에 전달합니다 (및 해당 인수 만). 중요한 것은 이것은 기본적으로 if is empty를 적용 하지 않을 것이며 , 이는 아마도 그러한 경우에 더 안전한 가정 일 것입니다.callback
callback
transition
D3 v5.8.0 +부터 .NET을 사용하는 공식적인 방법이 transition.end
있습니다. 문서는 다음과 같습니다.
https://github.com/d3/d3-transition#transition_end
Bostock의 실제 사례는 다음과 같습니다.
https://observablehq.com/@d3/transition-end
기본 아이디어는를 추가하는 것만으로도 .end()
전환이 모든 요소 전환이 완료 될 때까지 해결되지 않는 promise를 반환한다는 것입니다.
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");
변수를 사용하여 전환 시간을 설정하여 비슷한 문제를 해결했습니다. 그런 setTimeout()
다음 다음 함수를 호출했습니다. 제 경우에는 예에서 볼 수 있듯이 전환과 다음 호출 사이에 약간 겹치는 부분을 원했습니다.
var transitionDuration = 400;
selectedItems.transition().duration(transitionDuration).style("opacity", .5);
setTimeout(function () {
sortControl.forceSort();
}, (transitionDuration * 0.75));