2013-04-02 4 views
1

버튼 클릭 후 JSON 데이터를 D3 막대 그래프로 업데이트하는 데 많은 시간을 할애하고 있습니다.중복 차트로 나타나는 D3 차트 업데이트

버튼을 클릭하여 문제를 해결하는 동안 D3 자바 스크립트가 버튼 클릭당 하나의 차트를 추가하므로 단순히 데이터를 업데이트하는 대신 중복 차트가 표시됩니다.

클릭 이벤트가 트리거 될 때마다 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 축을 추가하는 코드 블록에도 똑같은 문제가 적용됩니다. 막대의 경우 입력 선택과 함께 업데이트 및 선택 항목을 처리합니다. 즉 치수를 설정하고 새 데이터를 기반으로 요소를 제거 할 수 있습니다.