2013-04-02 36 views
1

我有一段時間試圖更新JSON數據去按D3點擊按鈕後直方圖。更新D3圖表導致重複的圖表

雖然我解決了按鈕點擊更新問題,但D3 javascript現在每個按鈕點擊附加一個圖表,導致重複圖表而不是簡單地更新數據。

我知道點擊事件每次觸發時都會調用D3代碼中的append(),但是我怎樣才能解決這個問題,因此每次點擊只有一個更新數據的圖表?

console.log('chart.js loaded'); 

$(document).ready(function() { 

    var vimeoVideoId = $('p#vimeoVideoId').text(); 
    var api = 'http://localhost:3001/videos/' + vimeoVideoId + '/json'; 

    function initData() { 
    $('#all-notes').click(function() { 
     getData(); 
    }); 
    } 

    function getData() { 
    $.getJSON(api, draw); 
    } 

    function draw(json) { 

    data = json; 
    var duration = data.duration; 

    var timeToSec = function(data) { 
     notes = []; 
     // convert min:sec to seconds 
     for(i=0; i < data.notes.length; i++) { 
     var min_sec = data.notes[i].timecode; 
     var tt = min_sec.split(':'); 
     var seconds = tt[0]*60+tt[1]*1; 
     notes.push(seconds); 
     } 
     return notes; 
    }; 

    noteTimes = timeToSec(data); 
    console.log(noteTimes); 

    // Formatters for counts and times (converting numbers to Dates). 
    var formatCount = d3.format(",.0f"), 
     formatTime = d3.time.format("%H:%M"), 
     formatMinutes = function(d) { return formatTime(new Date(2012, 0, 1, 0, d)); }; 

    var margin = {top: 10, right: 20, bottom: 30, left: 20}, 
     width = 550; 
     height = 285; 

    var x = d3.scale.linear() 
     .domain([0, duration]) 
     // .domain([0, d3.max(noteTimes)]) 
     .range([0, width]); 

    // Generate a histogram using twenty uniformly-spaced bins. 
    var data = d3.layout.histogram() 
     .bins(x.ticks(50)) 
     (noteTimes); 

    var y = d3.scale.linear() 
     .domain([0, d3.max(data, function(d) { return d.y; })]) 
     .range([height, 0]); 

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

    var svg = d3.select("#chartSet").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 + ")"); 

    var bar = svg.selectAll(".bar") 
     .data(data) 
     .enter().append("g") 
     .attr("class", "bar") 
     .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); 

    bar.append("rect") 
     .attr("x", 1) 
     .attr("width", x(data[0].dx) - 1) 
     .attr("height", function(d) { return height - y(d.y); }); 

    bar.append("text") 
     .attr("dy", ".75em") 
     .attr("y", 6) 
     .attr("x", x(data[0].dx)/2) 
     .attr("text-anchor", "middle") 
     .text(function(d) { return formatCount(d.y); }); 

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

    initData(); 

}); 

回答

5

要處理創建和更新,您將不得不重新組織如何編寫draw函數。

function draw(json) { 

    // Initialization (few wasted CPU cycles) 
    // ... 

    // Update hook 
    var svg = d3.select("#chartSet").data([data]); 

    // Enter hook 
    var svgEnter = svg.enter(); 

    // Enter cycle 
    svgEnter.append("svg") 
     .append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

    // Update cycle 
    svg 
     .attr("width", width + margin.left + margin.right) 
     .attr("height", height + margin.top + margin.bottom); 

    // Exit cycle (not really needed here) 
    svg.exit().remove(); 

    // Update hook 
    var bar = svg.selectAll(".bar") 
     .data(data) 

    // Enter hook 
    var barEnter = bar.enter(); 

    // Enter cycle 
    var barG_Enter = barEnter 
         .append("g") 
         .attr("class", "bar") 
    barG_Enter 
     .append("rect") 
     .attr("x", 1); 

    barG_Enter 
     .append("text") 
     .attr("dy", ".75em") 
     .attr("y", 6) 
     .attr("text-anchor", "middle"); 

    // Update cycle 
    bar.attr("transform", function(d) { 
     return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); 

    bar.select("rect") 
     .attr("width", x(data[0].dx) - 1) 
     .attr("height", function(d) { return height - y(d.y); }); 

    bar.select("text") 
     .attr("x", x(data[0].dx)/2) 
     .text(function(d) { return formatCount(d.y); }); 

    // Exit cycle 
    bar.exit().remove(); 

    // Enter cycle 
    svgEnter.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis); 

    // Update cycle 
    svg.select('g.x.axis') 
     .call(xAxis); 
} 

classical enter-update-exit圖案在this article on making reusable graphs時改善。這個答案嚴重依賴於這種模式。

使用閉包稍微好一點的實現,您將能夠保存每次初始化時浪費的少量CPU週期。

0

您可以在單擊按鈕時調用的函數外部創建SVG,也可以檢查它是否存在,如果不存在,只添加它。也就是說,類似於

var svg = d3.select("svg"); 
if(svg.empty()) { 
    // code for appending svg 
} 

同樣的事情適用於附加x軸的函數末尾的代碼塊。對於條形圖,除了輸入選擇外,您只需處理更新和退出選擇,即設置維度並根據新數據刪除元素。