2013-05-02 21 views
9

Sto lavorando con D3.js. Ho avuto transizioni lavorando bene, ma devo solo un problema: se una seconda transizione inizia prima della prima si finisce,D3.js: interrompere le transizioni interrotte?

questo è un JSFiddle dimostrando il problema: http://jsfiddle.net/kqxhj/11/

Funziona bene la maggior parte del tempo - CDG e LAX vengono aggiunti e rimossi man mano che i dati cambiano, ma se fai clic due volte in rapida successione sul pulsante, noterai che i nuovi elementi non compaiono.

Questa è la carne del mio codice:

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

ho cercato di aggiungere alcune istruzioni di debug per capire cosa sta succedendo, ma tutto quello che posso vedere è che quando succede, la selezione uscita ha 4 elementi in, non 3 - Non capisco perché sia ​​così.

C'è un modo, sia in D3 o in JavaScript di base, che posso garantire che le transizioni non si sovrappongano?

+1

È necessario ascoltare l'evento ['end'] (https://github.com/mbostock/d3/wiki/Transitions#wiki-each) e avviare la transizione successiva solo dopo che si è verificata. In alternativa, guarda in ['transition.transition()'] (https://github.com/mbostock/d3/wiki/Transitions#wiki-transition). Ecco un [ottimo articolo] (http://bost.ocks.org/mike/transition/#life-cycle) che dovresti controllare. –

+1

Inoltre, la rimozione avviene alla fine della transizione, quindi non è necessario creare due transizioni di uscita solo per rimuovere i nodi. Vedi la [documentazione di transition.remove] (https://github.com/mbostock/d3/wiki/Transitions#wiki-remove). – mbostock

risposta

5

In D3, le transizioni più recenti interrompono e sovrascrivono sempre le transizioni più vecchie. Potresti risolvere il problema di progettazione utilizzando the each() method within your selection. ad es.

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

Grazie. Non sono sicuro di come applicarlo al mio caso specifico, però - vuoi dire qualcosa come aggiungere il metodo 'each' alle mie transizioni di aggiornamento, quindi inserire la transizione di uscita all'interno di quella chiamata 'each'? – Richard

8

Cosa sta succedendo è che la rappresentazione dei dati "ri-entra" prima che sia stato rimosso dal DOM (perché il remove() chiamata è incatenato su una transizione). Tuttavia, se la rappresentazione dei dati non è stata ancora rimossa dal DOM, la selezione enter() non conterrà quei dati perché già esiste! Eppure, la transizione continuerà a essere eseguita e la rappresentazione dei dati scomparirà senza la possibilità di "reinserire".

Quello che devi fare è dare una sorta di identificatore agli elementi in uscita. Per esempio:

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

Poi, quando si aggiorna la selezione, se un elemento "rientrò", annullare la transizione in uscita e riportarlo al suo stato originale:

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 

ho ottimizzato il vostro violino per dimostrare la soluzione: http://jsfiddle.net/hX5Tp/

Ecco un violino messo a nudo giù per dimostrare il problema (e la soluzione) in modo chiaro: http://jsfiddle.net/xbfSU/

+1

Questo approccio è stato intelligente. Grazie! – swenedo

9

AGGIORNAMENTO: dalla versione 3.5 di D3 (ottobre 2014), è possibile eseguire transizioni concomitanti su elementi tramite l'utilizzo di named transitions. Devi semplicemente aggiungere un nome diverso ad ogni transizione.

+3

Ho trovato questo utile. Quando si aggiungono due transizioni con lo stesso nome a un oggetto, le transizioni sono esclusive, cioè il secondo interrompe/annulla la prima transizione. – swenedo

+3

Questa era la risposta che stavo cercando – gray