2017-02-13 2 views
2

Ich habe eine D3 (v4) Visualisierung mit vielen Formen, die in einigen Fällen innerhalb von etwa drei Sekunden zu neuen Positionen animieren. Diese Formen haben Klick- und Mouseover-Ereignis-Listener, die nur dann aktiv sein sollen, wenn sich der Viz nicht bewegt.Ereignisse in d3 kurzschließen?

Die naive Art, dies zu tun, ist einfach. Ich habe eine boolean Variable is_animating genannt, den true gesetzt wird, wenn die Animation beginnt und false auf dem Rückruf, so dass ich nur diese zu dem Ereignis-Listener hinzugefügt:

shapes.on("click", function(d) { 
    if (is_animating) { 
    return; 
    } 
    // otherwise, business as usual 
}) 

Das ist in Ordnung, aber ich plane eine Menge hinzufügen Event-Listener zu den Shapes und würden es lieben, wenn es eine elegantere Möglichkeit gäbe, die Ereignisse, die höher im Bubbling sind, abzufangen und dies nur einmal zu tun, anstatt diese Prüfung zu jedem Event hinzuzufügen. Aber ich verstehe nicht ganz d3.event und wie es sprudelt. Gibt es einen einfachen "Master-Event-Listenet", wenn Sie so wollen, würde das jedes Mal ausgelöst werden, wenn ein Benutzer versucht, etwas zu tun, was das Event kurzschließen könnte, wenn is_animating wahr ist?

Antwort

3

Es gibt einen Weg in der D3-Überleitungs-API, um zu steuern, ob einem bestimmten Knoten aktive Übergänge zugeordnet sind (d3.active).

Sie könnten damit aktive Übergänge auf einem Knoten erkennen, ohne eine zusätzliche Variable einzuführen.

shapes.on("click", function(d) { 
    if (d3.active(this)) { 
    return; 
    } 
    // otherwise, business as usual 
}) 
+0

Danke, gut zu wissen! Dies würde immer noch bedeuten, stattdessen alle Zuhörer zu überprüfen, aber sehr nützliche Informationen. –

0

Wenn es auf die Art und Weise anwendbar ist man Dinge festgelegt haben, können Sie warten, bis der Übergang endet, bevor die Ereignis-Listener registriert:

shapes 
    .transition() 
    .attr(...) // apply new positions, styles, etc 
    .on('end', function() { 
    // called per element once its transition has completed 
    d3.select(this) 
     .on('click', function() { /* business as usual */ }) 
    }) 

Eine weitere nützliche Bit, die für Sie ins Spiel kommen könnten ist, dass Sie die Ereignis-Listener nicht unbedingt in der shapes-Auswahl registrieren müssen, die mehrere Listener ergibt. Stattdessen können Sie die Ereignisse ihrer Eltern abonnieren. Wenn das Elternteil ein svg in einer d3 Auswahl wäre, würde es so aussehen

svg // assumes svg is a d3 selection containing every shape 
    .on('click', function() { 
    // to get the clicked element 
    d3.select(d3.event.target) 
     .attr(...) 

    // or, if you just want d, the datum of the shape 
    // that was clicked: 
    var d = select(d3.event.target).datum() 
    }) 

Ich glaube nicht, es gibt einen Weg, um das Blubbern zu verhindern, wie Sie beschrieben. Ich weiß nicht warum; Ich würde erwarten, dass es funktioniert, aber meine Tests waren nicht erfolgreich. Es sollte jedoch angemerkt werden, dass, selbst wenn Sie in der Lage wären, die Verbreitung zu stoppen, es die Übertragung von Kind zu Elternteil, NICHT Eltern zu Kind, wäre.

+0

Beide gute Ideen! Ich stimme zu, dass es scheint, als ob es eine sprudelnde Lösung geben sollte, aber ich kann es auch nicht zur Arbeit bringen - und einen guten Punkt in Bezug auf die Richtung. Vielleicht ist die Lösung, während der _capturing_ Phase abzufangen? –