Potentemente (ma fastidiosamente) d3.js a volte ti costringe a ripetere se stessi per semplici visualizzazioni. Se si dice che si desidera creare un elemento con attributi derivati dai dati in un determinato modo, e successivamente si desidera passare tali attributi a nuovi dati, è necessario ripetere nuovamente come ricavare i valori (nel caso in cui si desideri fare qualcosa di diverso, come un diverso layout visivo). Come dice @Andrew, devi dirgli cosa fare quando transita.
È possibile aggirare il 'problema' seguendo questo schema:
var foo = d3.select('foo');
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar');
items.exit().remove();
items
.attr('foo',function(d){ return d });
}
In 2.0 quando si append()
nuovi articoli in enter()
vengono automaticamente aggiunti alla selezione originale associazione a dati, in modo che le chiamate al attr()
e ciò che in seguito non si applicherà a loro. Ciò consente di utilizzare lo stesso codice sia per l'impostazione dei valori iniziali che per l'aggiornamento dei valori.
Poiché non si desidera ricreare il wrapper SVG ogni aggiornamento, è necessario creare questo al di fuori della funzione redraw
.
Se si desidera eseguire le transizioni:
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar')
.attr('opacity',0)
.attr('foo',initialPreAnimationValue);
items.exit().transition().duration(500)
.attr('opacity',0)
.remove();
items.transition.duration(500)
.attr('opacity',1)
.attr('foo',function(d){ return d });
}
Nota che i soci di cui sopra oggetti con i dati di indice. Se si desidera eliminare un punto dati intermedio per svanire quel punto dati prima di rimuoverlo (invece di rimuovere l'ultimo elemento e trasformare ogni altro elemento in modo che assomigli a quello), è necessario specificare un valore di stringa univoco (non indicizzato) da associare. ogni prodotto con:
var data = [
{id:1, c:'red', x:150},
{id:3, c:'#3cf', x:127},
{id:2, c:'green', x:240},
{id:4, c:'red', x:340}
];
myItems.data(data,function(d){ return d.id; });
si può vedere un esempio di questo e giocare con lui in diretta su my D3.js playground.
Innanzitutto, vedere cosa succede quando si commenta una delle righe di dati e quindi di nuovo. Quindi, rimuovere il parametro ƒ('id')
dalla chiamata a data()
sulla riga 4 e riprovare a commentare e nelle righe di dati.
Edit: In alternativa, come commentato dal mbostock illustre, è possibile utilizzare selection.call()
insieme ad una funzione riutilizzabile come un modo per asciugare il tuo codice:
var foo = d3.select('foo');
function redraw(someArray){
var items = foo.selectAll('bar').data(someArray);
items.enter().append('bar').call(setEmAll);
items.exit().remove();
items.call(setEmAll);
}
function setEmAll(myItems){
myItems
.attr('foo',function(d){ return d*2 })
.attr('bar',function(d){ return Math.sqrt(d)+17 });
}
Come indicato sopra, .call()
richiama una funzione e passa lungo la selezione come argomento, in modo da poter eseguire la stessa impostazione sulla selezione in più posizioni.
Risposta straordinaria, grazie. Sto ancora cercando di capire la maggior parte di questa roba, ma questo sarà un vero aiuto! – Richard
Risposta riflessiva. Puoi anche scrivere la tua funzione 'redraw' in modo compatibile con [selection.call] (https://github.com/mbostock/d3/wiki/Selections#wiki-call). Correlati: [Verso grafici riutilizzabili] (http://bost.ocks.org/mike/chart/). – mbostock
@mbostock Ooh, è molto utile; Non avevo mai visto '.call()' prima. Sono solo un novizio di D3.js che aiuta dove posso. Modificherò per includere tali informazioni (e farò un passaggio completo attraverso i documenti per cercare di inserire tutte le possibilità nella mia testa). – Phrogz