在转换结束时调用回调

IT技术 javascript d3.js transition
2021-01-16 01:10:24

我需要使用D3.js制作一个 FadeOut 方法(类似于 jQuery)我需要做的是使用transition().

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

问题是我需要一个回调来实现转换完成的时间。如何实现回调?

6个回答

您想监听转换的“结束”事件。

// 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)

如果指定了类型,则为转换事件添加一个侦听器,同时支持“开始”和“结束”事件。将为转换中的每个单独元素调用侦听器,即使转换具有恒定的延迟和持续时间。start 事件可用于在每个元素开始转换时触发瞬时变化。结束事件可用于通过选择当前元素this和派生新转换来启动多阶段转换。在结束事件期间创建的任何过渡都将继承当前的过渡 ID,因此不会覆盖先前安排的较新的过渡。

有关更多详细信息,请参阅有关该主题的论坛主题

最后,请注意,如果您只想在元素淡出后(过渡完成后)移除它们,您可以使用transition.remove().

所以,我对这种从过渡结束继续的方式的问题是它运行你的函数 N 次(对于过渡元素集中的 N 个项目)。这有时远非理想。
2021-03-16 01:10:24
我有同样的问题。希望它在最后一次删除后运行一次该功能
2021-03-17 01:10:24
如何仅在 a 的所有转换完成d3.selectAll()后(而不是在每个元素完成后)执行回调换句话说,我只想在所有元素完成转换后回调一个函数。
2021-03-26 01:10:24
非常感谢你。这是一个 GREAT GREAT 库,但要在文档中找到重要信息并不容易。
2021-03-31 01:10:24
嗨,堆栈/组条形图的第一个链接指向一个 Observable 笔记本,它不使用任何.each事件侦听器,也不使用"end"事件。它似乎没有“链接”转换。第二个链接指向一个不适合我加载的 github。
2021-04-01 01:10:24

迈克·博斯托克的解决方案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(); }
2021-03-18 01:10:24
@kashesandr 可以简单地什么都不做,因为用户将体验到相同的效果:(在转换结束时没有回调调用)function endall(transition, callback){ if(!callback) return; // ... } 或者,因为在没有回调的情况下调用此函数无疑是一个错误,抛出异常接缝到是合适的处理方式我觉得这个case不需要太复杂的Exception function endall(transition, callback){ if(!callback) throw "Missing callback argument!"; // .. }
2021-03-19 01:10:24
因此,当我们有分离enter()exit()转换,并且想要等到所有三个都完成时,我们需要将代码放入回调中以确保它被调用了三次,对吗?D3好乱啊!我希望我选择了另一个图书馆。
2021-04-02 01:10:24
我应该补充一点,我意识到您的回答解决了我所困扰的一些问题,我可以编写一个实用程序来应用它。但是我还没有找到一种优雅的方法来应用它并且仍然允许对每个转换进行额外的自定义,特别是当新旧数据的转换不同时。我确定我会想出一些办法,但是“在所有这些转换完成后调用这个回调”似乎是一个应该在像 D3 这样成熟的库中开箱即用的用例。所以看起来我选择了错误的库——并不是 D3 的错。Anyhoo,感谢您的帮助。
2021-04-02 01:10:24
if (!callback) callback = function(){}; 为什么不立即返回,或者抛出异常?无效的回调确实违背了这个规则的全部目的,为什么要像盲人钟表匠那样去执行呢?:)
2021-04-13 01:10:24

现在,在 d3 v4.0 中,有一个工具可以显式地将事件处理程序附加到转换:

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

要在转换完成时执行代码,您只需要:

d3.select("#myid").transition().style("opacity", "0").on("end", myCallback);
美丽的。事件处理程序很糟糕。
2021-04-03 01:10:24
还有transition.remove()( link ),它处理从视图中转换元素的常见用例:`“对于每个选定的元素,只要元素没有其他活动或挂起的转换,就在转换结束时删除该元素。如果元素有其他活动或挂起的转换,什么都不做。”
2021-04-05 01:10:24
看起来这被称为转换应用于的 PER 元素,根据我的理解,这不是问题所在。
2021-04-08 01:10:24

一种稍微不同的方法也适用于有许多转换且每个元素同时运行的情况:

var transitions = 0;

d3.select("#myid").transition().style("opacity","0").each( "start", function() {
        transitions++;
    }).each( "end", function() {
        if( --transitions === 0 ) {
            callbackWhenAllIsDone();
        }
    });
谢谢,这对我来说很好用。我试图在加载离散条形图后自动自定义 x 轴标签方向。自定义无法在加载之前生效,这提供了一个事件挂钩,我可以通过它来执行此操作。
2021-03-27 01:10:24

以下是 Mike Bostock解决方案的另一个版本,其灵感来自 @hughes 对 @kashesandr 回答的评论。它在transition's 结束时进行单个回调

给定一个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即使为空,也将应用传递的值。这也会将任何其他参数转发给(并且仅这些参数)。重要的是,默认情况下不会应用if为空,这在这种情况下可能是更安全的假设。transition callbackcallbacktransition

不要真的认为我们需要 drop 函数或参数传递,因为可以通过包装函数或使用 bind 来实现相同的效果。否则我认为这是一个很好的解决方案 +1
2021-03-22 01:10:24
奇迹般有效 !
2021-03-27 01:10:24
这很好,我喜欢。
2021-03-30 01:10:24
谢谢@kashesandr。这确实受到了您的回答的启发!
2021-04-02 01:10:24
看到这个回复,.end() 现已正式添加 - stackoverflow.com/a/57796240/228369
2021-04-12 01:10:24