web-dev-qa-db-fra.com

D3: Comment actualiser un graphique avec de nouvelles données?

J'ai créé un tableau D3 Donut. Voici mon code:

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

J'ai un formulaire simple sur ma page Web qui affiche un menu déroulant avec plusieurs options. Chaque fois qu'un utilisateur modifie une valeur du formulaire, un nouveau jeu de données est envoyé à mon script (settings.dataset) et le donut est redessiné sur la page.

Le problème est que certaines des valeurs de l'ensemble de données précédent restent dans le DOM. Dans la sortie de la console ci-dessous, vous pouvez voir que le deuxième jeu de données ne comporte que deux éléments. Le troisième provient du jeu de données précédent. Cela dérange le graphique, car il affiche une valeur qui ne devrait pas être là.

enter image description here

Ma question: comment effacer les anciennes valeurs? J'ai lu sur .exit() et .remove(), mais je n'arrive pas à comprendre ces méthodes.

31
24ma13wg

Créez une fonction qui dessine le gâteau quand il est créé et mis à jour.

Les nouvelles données doivent être ajoutées au graphique en utilisant enter() et les anciennes données doivent être supprimées en utilisant exit().remove()

C'est aussi simple que cela:

  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()

Code de travail complet -> [~ # ~] jsfiddle [~ # ~]

21
CuriousSuperhero

Il existe deux étapes pour implémenter l’effet "redessiner" souhaité:

Tout d'abord, je suppose que vous voulez que le canevas svg ne soit dessiné qu'une seule fois lorsque la page est chargée pour la première fois, puis mettez à jour le graphique dans le svg au lieu de supprimer et de redessiner le 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")  

Deuxièmement, pour comprendre enter(), exit(), il existe de nombreux excellents tutoriels à ce sujet. Dans votre cas, je suggérerais de dessiner le beignet comme ceci:

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()
7
fengshuo
//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");
4