2016-04-29 16 views
0

Ich versuche, eine Multi-Serie Liniendiagramm zu erstellen (basierend auf dem Beispiel von Mike Bostock), aber zwischen mehreren Datensätzen wechseln. Ich habe die Linien zum Ein- und Ausstieg bekommen, aber die Beschriftungen für jede Zeile bleiben stehen, nachdem sie verschwunden sein sollten. Screenshot at this link.D3 Exit mehrere Serien Liniendiagramm Etiketten auf Übergang

Darüber hinaus sind die Linien auf eine ungerade Art und Weise Übergang; fast so, als ob sie nur die selbe Linie erweitern würden, um eine neue zu erstellen (Second screenshot at this link).

Hier ist der relevante Teil meines Codes (wo ich die Linien zu zeichnen und fügen Sie Labels):

var line = d3.svg.line() 
 
     .interpolate("basis") 
 
     .x(function(d) { return x(d.Date); }) 
 
     .y(function(d) { return y(d.candidate); }); 
 

 
    var person = svg_multi.selectAll(".candidate") 
 
     .data(people); 
 

 
    var personGroups = person.enter() 
 
     .append("g") 
 
     .attr("class", "candidate"); 
 

 
    person 
 
     .enter().append("g") 
 
     .attr("class", "candidate"); 
 

 
    personGroups.append("path") 
 
     .attr("class", "line") 
 
     .attr("d", function(d) { return line(d.values); }) 
 
     .style("stroke", function(d) { return color(d.name); }); 
 

 
    var personUpdate = d3.transition(person); 
 

 
    personUpdate.select("path") 
 
     .transition() 
 
     .duration(1000) 
 
     .attr("d", function(d) { 
 
      return line(d.values); 
 
     }); 
 

 
    person 
 
     .append("text") 
 
     .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) 
 
     .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }) 
 
     .attr("x", 3) 
 
     .attr("dy", ".35em") 
 
     .text(function(d) { return d.name; }); 
 

 
    person.selectAll("text").transition() 
 
     .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }); 
 

 
    person.exit().remove();

Antwort

0

Sie sind jedes Mal für jede Person ein neues Textelement anhängt Sie machen und nicht die alten entfernen. Vermutlich wird der von Ihnen gepostete Code jedes Mal ausgeführt, wenn Sie das Diagramm mit neuen Daten zeichnen wollen, so dass Sie jedes Mal mehr Textelemente erhalten, als die vorhandenen zu aktualisieren. Sie müssen nur an die "Enter" -Auswahl anhängen. Sie haben dies direkt an den Pfadelementen vorgenommen, sodass Sie den Text nur mehr wie den Pfad verwenden müssen. Ich habe Ihr Beispiel mit Kommentaren aktualisiert, um hervorzuheben, was ich geändert habe.

var line = d3.svg.line() 
 
    .interpolate("basis") 
 
    .x(function(d) { return x(d.Date); }) 
 
    .y(function(d) { return y(d.candidate); }); 
 

 
var person = svg_multi.selectAll(".candidate") 
 
    // I added a key function here to make sure you always update the same 
 
    // line for every person. This ensures that when you re draw with different 
 
    // data, the line for Trump doesn't become the line for Sanders, for example. 
 
    .data(people, function(d) { return d.name}); 
 

 
var personGroups = person.enter() 
 
    .append("g") 
 
    .attr("class", "candidate"); 
 

 
// This isn't needed. The path and text get appended to the group above, 
 
// so this one just sits empty and clutters the DOM 
 
// person 
 
// .enter().append("g") 
 
// .attr("class", "candidate"); 
 

 
personGroups.append("path") 
 
    .attr("class", "line") 
 
    // You do this down below, so no need to duplicate it here 
 
    // .attr("d", function(d) { return line(d.values); }) 
 
    .style("stroke", function(d) { return color(d.name); }); 
 
    
 
// Append the text element to only new groups in the enter selection 
 
personGroups.append("text") 
 
    // Set any static attributes here that don't update on data 
 
    .attr("x", 3) 
 
    .attr("dy", ".35em"); 
 

 
var personUpdate = d3.transition(person); 
 

 
personUpdate.select("path") 
 
    .transition() 
 
    .duration(1000) 
 
    .attr("d", function(d) { 
 
    return line(d.values); 
 
    }); 
 

 
person.select("text") 
 
    // You don't have to do this datum call because the text element will have 
 
    // the same data as its parent, but it does make it easier to get to the last 
 
    // value in the list, so you can do it if you want 
 
    .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) 
 
    .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }) 
 
    .text(function(d) { return d.name; }); 
 

 
// Remove this. You don't need it anymore since you are updating the text above 
 
// person.selectAll("text").transition() 
 
// .attr("transform", function(d) { return "translate(" + x(d.value.Date) + "," + y(d.value.candidate) + ")"; }); 
 

 
person.exit().remove();

Der Schlüssel zu Ihrer Frage wirklich tat nur personGroups.append('text') statt person.append('text'). Der Rest war nur, dass ich über Bord ging und auf andere Möglichkeiten hinwies, um Ihren Code zu verbessern, der das Verständnis und die Pflege erleichtern sollte.

+0

Danke, das hat funktioniert! – user3740848

Verwandte Themen