2016-05-23 111 views
2

我一直在嘗試使用D3.js,現在有了這個條形圖,我必須在按鈕單擊時動態刷新。D3.js:動態更改條形圖

我已經將它包裝在一個函數中,但是,似乎並不奏效。

什麼是問題,我該如何解決?

代碼:

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

我打電話它構成了我的html文件。 例如:

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

原始數據:

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 

更新時間:

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

我只看到你定義了'.enter',但你還需要'.update'和'.exit'來處理更新後的數據 – Fabricator

+0

我如何添加它們? @Fabricator – QuikProBroNa

+0

你能提供原始和更新的數據嗎? – Fabricator

回答

1

我可以看到第一眼2個問題:

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

你應該做的兩個步驟:

// 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); 

  • 您在enter選擇只transitionning
    • 您在每次更新

    你應該再創建它們重新創建軸,中庸之道更新動態值updateChart

    在啓動時:

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

    在更新:

    // 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

太棒了!但是,我該如何停止重新創建x和y軸? 如果我刪除了創建它們的代碼並將它們放在函數外面,它們就會出現錯誤 – QuikProBroNa

+1

檢查我的更新,我詳細介紹了一些更新函數中必須包含的內容 – codename44

+0

非常感謝! 但我的代碼仍然存在一個問題,我無法弄清楚。 即使值爲...,顏色一次設置也不會更改...爲什麼會發生這種情況?我在更新中附加了「fill」部分... – QuikProBroNa

-1

首先,您需要設置一個ID,當你輸入的數據:

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 

然後你需要做一個功能w母雞更新了所有的值

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

這是一個理解數據輸入和更新之間差異的例子。當您設置「.data(數據,函數(d,i){返回d.ID;})」時,爲d3提供期貨更新的ID非常重要。