2013-06-13 14 views
18

Sto usando V3 della popolare libreria d3 e fondamentalmente voglio avere tre transizioni, seguite l'una dall'altra: La prima transizione dovrebbe essere applicata alla selezione dell'uscita, la seconda all'aggiornamento selezione e la terza alla selezione di invio. Dovrebbero essere concatenati in modo tale che quando una delle selezioni è vuota, la relativa transizione venga saltata. Cioè quando non c'è una selezione di uscita, la selezione dell'aggiornamento dovrebbe iniziare immediatamente. Finora, ho creato questo codice (usando la funzione delay).d3: Come concatenare correttamente le transizioni su selezioni diverse

// DATA JOIN 
var items = d3.select('#data').selectAll('.item'); 
items = items.data(data, function(d){ 
    return d.twitter_screenname; 
}); 


// EXIT 
items.exit().transition().duration(TRANSITION_DURATION).style('opacity', 0).remove(); 

// UPDATE 
// Divs bewegen 
items.transition().duration(TRANSITION_DURATION).delay(TRANSITION_DURATION * 1) 
    .style('left', function(d, i) { 
     return positions[i].left + "px"; 
    }).style('top', function(d, i) { 
     return positions[i].top + "px"; 
    }); 

// ENTER 
// Divs hinzufügen 
var div = items.enter().append('div') 
    .attr('class', 'item') 
    .style('left', function(d, i) { 
     return positions[i].left + "px"; 
    }).style('top', function(d, i) { 
     return positions[i].top + "px"; 
    }); 

div.style('opacity', 0) 
    .transition().duration(TRANSITION_DURATION).delay(TRANSITION_DURATION * 2) 
    .style('opacity', 1); 

Innanzitutto non permette di "saltare" transizioni e secondariamente Credo ci sia un modo migliore di delay. Ho guardato allo http://bl.ocks.org/mbostock/3903818 ma non ho davvero capito cosa sta succedendo.

Inoltre, in qualche modo la scrittura items.exit().transition().duration(TRANSITION_DURATION).remove() non funziona con lo items, probabilmente perché non sono elementi SVG ma div s.

risposta

30

Sicuro. Qui ci sono due modi.

Innanzitutto, è possibile utilizzare un delay esplicito, che viene quindi calcolato utilizzando selection.empty per saltare le transizioni vuote. (Questa è solo una piccola modifica di quello che hai già.)

var div = d3.select("body").selectAll("div") 
    .data(["enter", "update"], function(d) { return d || this.textContent; }); 

// 2. update 
div.transition() 
    .duration(duration) 
    .delay(!div.exit().empty() * duration) 
    .style("background", "orange"); 

// 3. enter 
div.enter().append("div") 
    .text(function(d) { return d; }) 
    .style("opacity", 0) 
    .transition() 
    .duration(duration) 
    .delay((!div.exit().empty() + !div.enter().empty()) * duration) 
    .style("background", "green") 
    .style("opacity", 1); 

// 1. exit 
div.exit() 
    .style("background", "red") 
    .transition() 
    .duration(duration) 
    .style("opacity", 0) 
    .remove(); 

http://bl.ocks.org/mbostock/5779682

Una cosa difficile qui è che si deve creare il passaggio sugli elementi di aggiornamento prima creati la transizione su gli elementi entranti; questo perché enter.append unisce gli elementi in entrata nella selezione di aggiornamento, e tu vuoi tenerli separati; vedere lo Update-only Transition example per i dettagli.

In alternativa, è possibile utilizzare transition.transition a chain transitions e transition.each per applicare queste transizioni concatenate alle selezioni esistenti. Nel contesto di transition.each, selection.transition eredita la transizione esistente anziché crearne una nuova.

var div = d3.select("body").selectAll("div") 
    .data(["enter", "update"], function(d) { return d || this.textContent; }); 

// 1. exit 
var exitTransition = d3.transition().duration(750).each(function() { 
    div.exit() 
     .style("background", "red") 
    .transition() 
     .style("opacity", 0) 
     .remove(); 
}); 

// 2. update 
var updateTransition = exitTransition.transition().each(function() { 
    div.transition() 
     .style("background", "orange"); 
}); 

// 3. enter 
var enterTransition = updateTransition.transition().each(function() { 
    div.enter().append("div") 
     .text(function(d) { return d; }) 
     .style("opacity", 0) 
    .transition() 
     .style("background", "green") 
     .style("opacity", 1); 
}); 

http://bl.ocks.org/mbostock/5779690

suppongo quest'ultimo è un po 'più idiomatica, pur utilizzando transition.each applicare transizioni selezioni (anziché transizioni Deriva con parametri di default) non è una caratteristica ampiamente noto.

+0

Correggetemi se ho torto, ma penso che ci sia un piccolo errore nel codice usando 'delay()' -Method. Quando non c'è transizione di aggiornamento (cioè nessun elemento cambia luogo), 'items.enter(). Empty()' equivale ancora a 'false', quindi elemens exit, quindi, per' duration' millisecondi non accade nulla, e quindi la transizione di invio inizia. Ma se non avviene alcuna transizione di aggiornamento visivo, voglio che la transizione di uscita sia seguita * immediatamente * dalla transizione di invio. Così salverò la transizione di aggiornamento come segue: – wnstnsmth

+0

'var updatedItems = div.transition() . Durata (durata) .delay (! Div.exit(). Empty() * durata)' e cambia '.delay ((! div.exit(). empty() +! div.enter(). empty()) * duration) 'in' .delay ((! div.exit(). empty() +! updatedItems.empty()) * durata) '. In questo modo funziona come richiesto. – wnstnsmth

Problemi correlati