2016-05-23 11 views
2

Ich habe jetzt ziemlich viel mit D3.js experimentiert und ich habe dieses Balkendiagramm, das ich dynamisch auf Knopfdruck aktualisieren muss.D3.js: Dynamisches Ändern des Balkendiagramms

Ich habe es in einer Funktion verpackt, aber das scheint nicht zu funktionieren.

Was ist das Problem und wie kann ich es lösen?

Code:

var margin = {top: 40, right: 20, bottom: 30, left: 40}, 
    width = 900, 
    height = 700; 

var x = d3.scale.ordinal() 
    .rangeRoundBands([0, width], .1); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left") 
    .ticks(10) 
    .tickFormat(d3.format("s")); 

var tip = d3.tip() 
    .attr('class', 'd3-tip') 
    .offset([-10, 0]) 
    .html(function(d) { 
    return "<strong>Popularity:</strong> <span style='color:teal'>" + d.popularity+"</span>"; 
    }) 

var svg = d3.select("#chart").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

svg.call(tip); 

function updateChart(concert){ 

d3.tsv(concert+".tsv", type, function(error, data) { 
    x.domain(data.map(function(d) { return d.month; })); 
    y.domain([0, 45]); 
    svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis); 

    svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 
    .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", "1em") 
     .style("text-anchor", "end") 
     .text("Popularity"); 

    var pops= svg.selectAll(".bar") 
     .data(data) 
    .enter().append("rect") 
     .attr("width", x) 
     .attr("fill", function(d) { 
     if (d.popularity> 30) { 
      return "#010"; 
     else 
      return "000"; 
     }) 
     .attr("class", "bar") 
     .attr("x", function(d) { return x(d.month); }) 
     .attr("width", x.rangeBand()) 
     .attr("y", height - 1) 
     .attr("height", 1); 

    pops.transition() 
     .duration(1000) 
     .delay(function (d, i) { 
     return i * 100; 
     }) 
     .attr("y", function(d) { return y(d.popularity); }) 
     .attr("height", function(d) { return height- y(d.popularity); }); 

    pops.on('mouseover', tip.show) 
     .on('mouseout', tip.hide); 

    }); 

} 

function type(d) { 
    d.popularity= +d.popularity; 
    return d; 
} 

Ich rufe es meine HTML-Datei bilden. ex:

<button onclick="updateChart('JB')">JB</button> 

Original Data:

month popularity 
January 24.6 
February 26.2 
March 28.4 
April 30.9 
May 32.9 
June 32.4 
July 30.7 
August 30.1 
September 29.7 
October 28.2 
November 26.1 
December 25 

Aktualisiert:

month popularity 
January 73 
February 72 
March 70 
April 69 
May 62 
June 57 
July 64 
August 66 
September 72 
October 77 
November 78 
December 77 
+0

Ich sehe nur, dass Sie '.enter' definiert haben, aber Sie benötigen auch' .update' und '.exit', um aktualisierte Daten zu verarbeiten – Fabricator

+0

Wie füge ich sie hinzu? @Fabricator – QuikProBroNa

+0

können Sie die ursprünglichen und aktualisierten Daten bereitstellen? – Fabricator

Antwort

1

I 2 Probleme auf den ersten Blick sehen:

  • Du transitionning nur auf der enter Auswahl:
// pops only contains the 'enter selection' (=new elements) 
var pops= svg.selectAll(".bar") 
     .data(data) 
    .enter().append("rect") 

// So the transition will be only on the 'enter selection' 
pops.transition()... 

Sie sollten es in zwei Schritten tun:

// pops now contains the 'update selection' (=existing elements) 
    var pops= svg.selectAll(".bar") 
     .data(data); 
// 'enter().append' creates elements but also add them automatically to the 'update selection' 
    pops.enter().append("rect"); 

// Here attributes will apply on the 'enter + update selection' (=all elements) 
    pops.attr("width", x) 
     .attr("fill", function(d) { 
     if (d.popularity> 30) { 
      return "#010"; 
     else 
      return "000"; 
     }) 
     .attr("class", "bar") 
     .attr("x", function(d) { return x(d.month); }) 
     .attr("width", x.rangeBand()) 
     .attr("y", height - 1) 
     .attr("height", 1); 
  • Du erstellst die Achse bei jedem Update

Sie sollten sie einmal erstellen und juste Update dynamische Werte in updateChart

Beim Start:

var x = d3.scale.ordinal() 
    .rangeRoundBands([0, width], .1); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left") 
    .ticks(10) 
    .tickFormat(d3.format("s")); 

var gXAxis = svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis); 

var gYAxis = svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis); 

Bei Update:

// Update domains 
x.domain(data.map(function(d) { return d.month; })); 
y.domain([0, 45]); 
// Update axis 
gXAxis.call(xAxis); 
gYAxis.call(yAxis); 
// You could even handle it smoothly via a transition: 
// gXAxis.transition().call(xAxis); 
// gYAxis.transition().call(yAxis); 
+0

Großartig! Aber wie höre ich damit auf, die X- und Y-Achse neu zu erstellen? Wenn ich den Code für die Erstellung entfernen und sie aus der Funktion, sind sie falsch formatiert – QuikProBroNa

+1

überprüfen Sie mein Update, ich detaillierte ein bisschen mehr, was in Update-Funktion sein muss – codename44

+0

Vielen Dank! Aber ein Problem besteht in meinem Code, ich bin nicht in der Lage, es herauszufinden. Die einmal eingestellte Farbe wird nicht geändert, auch wenn die Werte ... Warum passiert das? Ich habe den "fill" -Teil im Update angehängt ... – QuikProBroNa

-1

Zuerst müssen Sie eine ID festgelegt, wenn die Eingangs Sie die Daten:

var pops= svg.selectAll(".bar") 
    .data(data, function(d,i){ return d.month; // this value most be an Id for each node }) 
pops.enter().append("rect"); // newest nodes 
update(); // updates nodes 
pops.exit().remove(); // remove exits nodes 

Dann Sie müssen eine Funktion w machen henne alle Werte für die Viz aktualisieren

function update(){ 
    pops 
    .attr("width", x) 
    .attr("fill", "#010") 
    .attr("class", "bar") 
    .attr("x", function(d) { return x(d.month); }) 
    .attr("width", x.rangeBand()) 
    .attr("y", height - 1) 
    .attr("height", 1); 
} 

Dies ist ein Beispiel für den Unterschied zwischen der Eingabe und Aktualisierung von Daten zu verstehen. Es ist sehr wichtig, wenn Sie die ".data (data, function (d, i) {return d.ID;})" für d3 eine ID für Futures-Updates angeben.