Вопрос по javascript – Вызвать обратный вызов в конце перехода

87

Мне нужно сделать метод FadeOut (похож на jQuery), используяD3.js, Что мне нужно сделать, это установить непрозрачность на 0, используяtransition().

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

Проблема в том, что мне нужен обратный вызов, чтобы понять, когда переход завершен. Как я могу реализовать обратный вызов?

Ваш Ответ

8   ответов
10

который также работает, когда есть много переходов с несколькими элементами, выполняющимися одновременно:

var transitions = 0;

d3.select("#myid").transition().style("opacity","0").each( "start", function() {
        transitions++;
    }).each( "end", function() {
        if( --transitions === 0 ) {
            callbackWhenAllIsDone();
        }
    });
Error: User Rate Limit Exceeded
45

в d3 v4.0, есть средство для явного присоединения обработчиков событий к переходам:

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

Чтобы выполнить код после завершения перехода, все что вам нужно:

d3.select("#myid").transition().style("opacity", "0").on("end", myCallback);
Error: User Rate Limit Exceededtransition.remove() (linkError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
119

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

// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
This demo uses the "end" event to chain many transitions in order. The donut example that ships with D3 also uses this to chain together multiple transitions. Here's my own demo that changes the style of elements at the start and end of the transition.

Из документации дляtransition.each([type],listener):

If type is specified, adds a listener for transition events, supporting both "start" and "end" events. The listener will be invoked for each individual element in the transition, even if the transition has a constant delay and duration. The start event can be used to trigger an instantaneous change as each element starts to transition. The end event can be used to initiate multi-stage transitions by selecting the current element, this, and deriving a new transition. Any transitions created during the end event will inherit the current transition ID, and thus will not override a newer transition that was previously scheduled.

See эта ветка форума по теме Больше подробностей.

Наконец, обратите внимание, что если вы просто хотите удалить элементы после их исчезновения (после завершения перехода), вы можете использоватьtransition.remove().

Error: User Rate Limit ExceededallError: User Rate Limit Exceededd3.selectAll()Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Tony
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededgist.github.com/miguelmota/3faa2a2954f5249f61d9
6

решение и вдохновленный @ hughes & apos; комментарий к ответу @ 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");

d3.transition.end будет применять пройденныйcallback даже с пустымtransition if количество миллисекунд указаноor if второй аргумент правдив. Это также перенаправит любые дополнительные аргументыcallback (и только те аргументы). Главное, это будетnot by default применитьcallback еслиtransition пусто, что, вероятно, является более безопасным предположением в таком случае.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
63

решение за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") });
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededenter()Error: User Rate Limit Exceededexit()Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededif (transition.size() === 0) { callback(); }
Error: User Rate Limit ExceededallError: User Rate Limit Exceeded
Error: User Rate Limit Exceededfunction endall(transition, callback){ if(!callback) return; // ... }Error: User Rate Limit Exceededfunction endall(transition, callback){ if(!callback) throw "Missing callback argument!"; // .. }
-2

ов.

var timer = null,
    timerFunc = function () {
      doSomethingAfterTransitionEnds();
    };

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

решение улучшено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");
-2

установив продолжительность переходов с помощью переменной. Тогда я использовалsetTimeout() вызвать следующую функцию. В моем случае я хотел слегка перекрыть переход и следующий вызов, как вы увидите в моем примере:

var transitionDuration = 400;

selectedItems.transition().duration(transitionDuration).style("opacity", .5);

setTimeout(function () {
  sortControl.forceSort();
}, (transitionDuration * 0.75)); 

Похожие вопросы