2013-05-02 13 views
9

Pracuję z D3.js. Mam przejścia pracuje ładnie, ale mam tylko jeden problem: jeśli drugie przejście rozpoczyna się przed pierwszym kończyD3.js: Przerwanie przejść jest przerywane?

To JSFiddle wykazując problemu: http://jsfiddle.net/kqxhj/11/

To działa dobrze przez większość czasu - CDG i LAX są dołączane i usuwane wraz ze zmianą danych - ale jeśli klikniesz przycisk dwa razy w krótkich odstępach czasu, zauważysz, że nowe elementy nie pojawiają się.

Jest to mięso z mojego kodu:

function update(data) { 

    var g = vis.selectAll("g.airport").data(data, function(d) { 
    return d.name; 
    }); 
    var gEnter = g.enter().append("g") 
    .attr("class", function(d) {  
    return "airport " + d.name; 
    }); 
    // Perform various updates and transitions... 
    [...] 

    // Remove exited elements. 
    g.exit().transition() 
    .duration(1000) 
    .attr("transform", "translate(0," + 1.5*h + ")"); 
    g.exit().transition().delay(1000) 
    .remove(); 
} 

d3.select('#clickme').on("click", function() { 
    update(current_data); 
}); 

Próbowałem dodać pewne oświadczenia debugowania, aby dowiedzieć się, co się dzieje, ale wszystko, co mogę zobaczyć, że kiedy to się stanie, wybór wyjście ma 4 elementy w, nie 3 - Nie rozumiem, dlaczego tak jest.

Czy istnieje sposób, czy w języku D3, czy w podstawowym kodzie JavaScript, że mogę zapewnić, że przejścia się nie nakładają?

+1

Musisz posłuchać zdarzenia ['end'] (https://github.com/mbostock/d3/wiki/Transitions#wiki-each) i rozpocząć następne przejście dopiero po jego wystąpieniu. Alternatywnie, spójrz na ['transition.transition()'] (https://github.com/mbostock/d3/wiki/Transitions#wiki-transition). Oto [świetny artykuł] (http://bost.ocks.org/mike/transition/#life-cycle), który powinieneś sprawdzić. –

+1

Usunięcie następuje również na końcu przejścia, więc nie trzeba tworzyć dwóch przejść wyjściowych tylko w celu usunięcia węzłów. Zapoznaj się z dokumentem [transition.remove] (https://github.com/mbostock/d3/wiki/Transitions#wiki-remove). – mbostock

Odpowiedz

5

W wersji D3 nowsze przejścia zawsze przerywają i zastępują starsze przejścia. Możesz rozwiązać swój problem projektowy za pomocą the each() method within your selection. np.

d3.select('.animated') 
.transition() 
.duration(1000) 
.attr({ 
    ... // Change something 
}) 
.each('end', function() { 
    d3.select(this) 
    .attr({ 
     ... // Change something else, after previous transition 
    }); 
}); 
+0

Dzięki. Nie jestem pewien, w jaki sposób mógłbym zastosować to do mojej konkretnej sprawy - masz na myśli coś takiego jak dołączenie metody "each" do moich przejść do aktualizacji, a następnie umieścić przejście wyjścia wewnątrz tego "każdego" połączenia? – Richard

8

Co się dzieje jest to, że reprezentacja danych „ponownie wejdzie”, zanim została usunięta z DOM (ponieważ remove() wywołanie jest przykuty na przejściu). Jeśli jednak reprezentacja danych nie została jeszcze usunięta z DOM, wybór enter() nie będzie zawierał tych danych, ponieważ już istnieje! A jednak twoje przejście będzie kontynuowane, a twoja reprezentacja danych zniknie bez możliwości "ponownego wejścia".

Co trzeba zrobić, to podać elementowi wyjściowemu jakiś identyfikator. Na przykład:

g.exit().classed('exiting', true); 

Następnie, po zaktualizowaniu wyboru, czy element „ponownie wszedł”, anulować przejście wychodzącego i doprowadzić go do stanu pierwotnego:

g.filter('.exiting') 
    .classed('exiting', false) 
    .transition() // new transition cancels the old one so that remove() isn't called 
     .attr('foo', 'bar'); // return to original state 

mam manipulowane swoje skrzypce do wykazania rozwiązanie: http://jsfiddle.net/hX5Tp/

Oto okrojona skrzypce wykazania problem (i rozwiązania), która jasno: http://jsfiddle.net/xbfSU/

+1

To podejście było sprytne. Dzięki! – swenedo

9

AKTUALIZACJA: Od wersji 3.5 D3 (październik 2014), możliwe jest wykonywanie równoczesnych przejść na elementach przy użyciu named transitions. Po prostu musisz dodać inną nazwę do każdego przejścia.

+3

Znalazłem to przydatne. Podczas dodawania dwóch przejść o tej samej nazwie do obiektu przejścia są wyłączne, tj. Drugie przerywa/anuluje pierwsze przejście. – swenedo

+3

To była odpowiedź, której szukałem – gray