在过渡期结束调用回调在过渡期结束调用回调(Invoke a callback at the end

2019-05-14 09:33发布

我需要使用(类似于jQuery的)一个淡出方法D3.js 。 我需要做的是使用不透明度设置为0 transition()

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

问题是,我需要一个回调时的过渡已经完成实现。 我怎样才能实现回调?

Answer 1:

你要听过渡的“结束”事件。

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

// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
  • 该演示采用了“结束”事件链许多过渡秩序。
  • 的甜甜圈示例附带D3也使用这对链在一起的多个转变。
  • 下面是我自己的演示改变在过渡的开始和结束元素的样式。

从用于文档transition.each([type],listener)

如果指定类型 ,增加了对过渡事件侦听器,同时支持“开始”和“结束”事件。 收听将被调用在过渡每个单独的元件,即使该过渡具有恒定延迟和持续时间。 启动事件可被用作每个元素开始切换到触发瞬时变化。 结束事件可以用于通过选择当前元素,以启动多级转换this ,并导出新的过渡。 结束事件期间创建的任何变化都将继承当前过渡ID,并且因此将不会覆盖先前调度的一个较新的过渡。

请参阅有关该主题的论坛主题的更多细节。

最后要注意的是,如果你只是想删除他们已经淡出后(过渡完成后)的元素,你可以使用transition.remove()



Answer 2:

迈克·博斯托克的解决方案与一个小更新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") });


Answer 3:

现在,在D3 V4.0,对事件处理程序明确地安装到过渡设施:

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

要当一个过渡已经完成执行代码,你需要的是:

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


Answer 4:

稍微不同的方法,作品也时有每个同时运行许多元素很多的转变:

var transitions = 0;

d3.select("#myid").transition().style("opacity","0").each( "start", function() {
        transitions++;
    }).each( "end", function() {
        if( --transitions === 0 ) {
            callbackWhenAllIsDone();
        }
    });


Answer 5:

以下是迈克·博斯托克的另一个版本的解决方案 ,并通过@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");

d3.transition.end将应用通过callback与空甚至transition ,如果指定的毫秒数,或者如果第二个参数是truthy。 这也将转发到任何额外的参数callback (只有那些参数)。 重要的是,这不会默认应用callback ,如果transition是空的,这可能是在这种情况下,一个更安全的假设。



Answer 6:

迈克·博斯托克的解决方案提高了通过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");


Answer 7:

实际上,有做到这一点使用定时器另一种方式。

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

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


Answer 8:

我通过设置使用变量转换的持续时间解决了类似的问题。 然后我用setTimeout()来调用一个函数。 就我而言,我想要的过渡,并在下次调用之间稍有重叠,因为你会在我的例子中看到:

var transitionDuration = 400;

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

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


文章来源: Invoke a callback at the end of a transition