2015-12-04 13 views
22

Ho creato un grafico a ciambella d3. Qui è il mio codice:D3: come aggiornare un grafico con nuovi dati?

var width = 480; 
var height = 480; 
var radius = Math.min(width, height)/2; 
var doughnutWidth = 30; 

var color = d3.scale.category10(); 

var arc = d3.svg.arc() 
.outerRadius(radius - 10) 
.innerRadius(radius - 70); 

var pie = d3.layout.pie() 
.sort(null) 
.value(function(d) { return d[1]; }); 

var dataset = settings.dataset; 
console.log(dataset); 

var svg = d3.select("body") 
.append("svg") 
.attr("width", width) 
.attr("height", height) 
.append("g") 
.attr("transform", "translate(" + width/2 + "," + height/2 + ")"); 

var path = svg.selectAll('path') 
.data(pie(dataset)) 
.enter() 
.append('path') 
.attr('d', arc) 
.attr('fill', function(d, i) { 
    return color(d.data[0]); 
}) 

Ho una forma semplice sulla mia pagina web che viene visualizzato un menu a tendina con diverse opzioni. Ogni volta che un utente modifica un valore nel modulo, viene inviato un nuovo set di dati al mio script (settings.dataset) e la ciambella viene ridisegnata sulla pagina.

Il problema è che alcuni dei valori del set di dati precedente rimangono nel DOM. Nell'output della console di seguito, è possibile vedere che il secondo set di dati ha solo due elementi. Il terzo proviene dal set di dati precedente. Questo sta rovinando il grafico, poiché sta visualizzando un valore che non dovrebbe essere lì.

enter image description here

La mia domanda: come faccio a cancellare i vecchi valori? Ho letto su .exit() e .remove(), ma non riesco a capire come funziona.

+0

quindi il codice che hai incollato sopra viene eseguito ogni volta su udate? – Cyril

+0

Sì, lo script viene chiamato ogni volta che un utente sceglie un'opzione diversa nel mio modulo. – 24ma13wg

+1

un problema che posso vedere è d3.select ("body") .append ("svg") che significa che si sta aggiungendo lo svg ogni volta durante l'aggiornamento. fai d3.select ("svg"). remove() per assicurarne la rimozione durante l'aggiornamento. – Cyril

risposta

7

Ci sono due passi per implementare l'effetto 'ridisegnare' che si desidera:

In primo luogo, suppongo si desidera che la svg tela per essere disegnato solo una volta quando la pagina viene caricata per la prima volta, e quindi aggiornare il grafico nella svg invece di rimuovere e ridisegnare la svg:

var svg = d3.select("body") 
       .selectAll("svg") 
       .data([settings.dataset]); 
// put data in an array with only one element 

// this ensures there is only one consistent svg on the page when data is updated(when the script gets executed) 
svg.enter().append("svg") 

in secondo luogo, la comprensione enter(), exit(), ci sono molti grandi tutorial su questo. Nel tuo caso, vorrei suggerire di disegnare la ciambella qualcosa di simile:

var path = svg.selectAll(".donut") 
      .data(settings.data) 

// bind data to elements, now you have elements belong to one of those 
// three 'states', enter, exit, or update 

// for `enter` selection, append elements 
path.enter().append("path").attr("d", arc).attr("fill", "teal") 

// for `update` selection, which means they are already binded with data 
path.transition().attrTween("d", someFunction) // apply transition here if you want some animation for data change 

// for `exit` selection, they shouldn't be on the svg canvas since there is no corresponding data, you can then remove them 
path.exit().remove() 
+0

Prendo il tuo punto: disegna il grafico una volta e poi aggiorna secondo la selezione dell'utente. Un po 'come questo: http: //bl.ocks.org/mbostock/1.346.410. Al momento sto caricando solo i dati a cui l'utente è interessato. In questo approccio ho bisogno di caricare tutti i dati e archiviarli in un array più grande, il che non è un grosso problema perché è una piccola quantità di dati. Dovrò riscrivere il codice che consegna i dati. Grazie per il suggerimento. – 24ma13wg

+0

Ridisegnare il grafico ogni volta sarebbe più adatto al mio caso d'uso, penso. – 24ma13wg

+0

Se vuoi dire che è necessario rimuovere e riaggiungere il percorso ogni volta, transizione() e exit() non saranno necessarie, quindi – fengshuo

17

Creare una funzione che (ri) disegna la torta quando viene creato e quando è aggiornato.

nuovi dati dovrebbero essere aggiunti alla torta con enter() e vecchi dati devono essere rimossi con exit().remove()

E 'semplice come questo:

path.enter().append("path") 
      .attr("fill", function(d, i) { return color(i); }) 
      .attr("d", arc) 
      .each(function(d) {this._current = d;}); 

    path.transition() 
      .attrTween("d", arcTween); 

    path.exit().remove() 

codice di lavoro completa ->JSFIDDLE

+1

Cosa fa '.each (function (d) {this._current = d;})' do? –

2
//remove and create svg 
d3.select("svg").remove(); 
var svg = d3.select("body").append("svg").attr("width","960").attr("height", "600"), 
inner = svg.append("g"); 
Problemi correlati