it-swarm.com.de

Rufen Sie am Ende eines Übergangs einen Rückruf auf

Ich muss eine FadeOut-Methode (ähnlich wie jQuery) mit D3.js erstellen. Ich muss die Deckkraft mit transition() auf 0 setzen.

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

Das Problem ist, dass ich einen Rückruf benötige, um festzustellen, wann der Übergang abgeschlossen ist. Wie kann ich einen Rückruf implementieren?

94
Tony

Sie möchten auf das "End" -Ereignis des Übergangs warten.

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

// old way
d3.select("#myid").transition().style("opacity","0").each("end", myCallback);
  • Diese Demo verwendet das "End" -Ereignis, um viele Übergänge der Reihe nach zu verketten.
  • Das Donut-Beispiel , das mit D3 geliefert wird, verwendet dies auch, um mehrere Übergänge miteinander zu verketten.
  • Hier ist meine eigene Demo , das den Stil der Elemente zu Beginn und am Ende des Übergangs ändert.

Aus der Dokumentation zu transition.each([type],listener) :

Wenn der Typ angegeben ist, wird ein Listener für Übergangsereignisse hinzugefügt, der sowohl Start- als auch Endereignisse unterstützt. Der Listener wird für jedes einzelne Element in der Überblendung aufgerufen, auch wenn die Überblendung eine konstante Verzögerung und Dauer aufweist. Das Startereignis kann verwendet werden, um eine sofortige Änderung auszulösen, wenn jedes Element mit dem Übergang beginnt. Mit dem Endereignis können mehrstufige Übergänge initiiert werden, indem das aktuelle Element this ausgewählt und ein neuer Übergang abgeleitet wird. Während des Endereignisses erstellte Übergänge erben die aktuelle Übergangs-ID und überschreiben daher keinen zuvor geplanten neueren Übergang.

Siehe dieser Forenthread zum Thema für weitere Details.

Beachten Sie schließlich, dass Sie transition.remove() verwenden können, wenn Sie die Elemente erst nach dem Ausblenden (nach Abschluss des Übergangs) entfernen möchten.

130
Phrogz

Mike Bostocks Lösung für v3 mit einem kleinen Update:

  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") });
65
kashesandr

In d3 v4.0 gibt es jetzt eine Funktion zum expliziten Anhängen von Ereignishandlern an Übergänge:

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

Um Code nach Abschluss eines Übergangs auszuführen, müssen Sie lediglich Folgendes tun:

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

Ein etwas anderer Ansatz, der auch funktioniert, wenn viele Übergänge mit vielen Elementen gleichzeitig ausgeführt werden:

var transitions = 0;

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

Das Folgende ist eine andere Version von Mike Bostocks Lösung und inspiriert von @ hughes 'Kommentar zu @ kashesandrs Antwort. Es wird ein einzelner Rückruf nach dem Ende von transition durchgeführt.

Eine drop -Funktion gegeben ...

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);
}

... wir können d3 folgendermaßen erweitern:

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;
}

Als JSFiddle .

Benutze transition.end(callback[, delayIfEmpty[, arguments...]]):

transition.end(function() {
    console.log("all done");
});

... oder mit einer optionalen Verzögerung, wenn transition leer ist:

transition.end(function() {
    console.log("all done");
}, 1000);

... oder mit optionalen callback Argumenten:

transition.end(function(x) {
    console.log("all done " + x);
}, 1000, "with callback arguments");

d3.transition.end Wird den übergebenen callback auch bei einem leeren transition anwenden if die Anzahl der Millisekunden wird angegeben oder if Das zweite Argument ist wahr. Dadurch werden auch alle zusätzlichen Argumente an callback weitergeleitet (und nur diese Argumente). Wichtig ist, dass dies nicht standardmäßig das callback anwendet, wenn transition leer ist, was in einem solchen Fall wahrscheinlich eine sicherere Annahme ist.

6
milos

Mike Bostocks Lösung wurde durch kashesandr + Überholen verbessert Argumente zur Rückruffunktion:

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");
0
int_ua