更新D3图表,导致重复图表 [英] Updating D3 chart resulting in duplicate charts

查看:210
本文介绍了更新D3图表,导致重复图表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个时间试图更新JSON数据到按钮点击后D3直方图的时间。

I am having a hell of a time trying to update JSON data going to a D3 histogram after a button click.

当我解决了按钮点击更新问题,D3 javascript现在每个按钮点击附加一个图表,从而产生重复的图表而不是简单地更新数据。

While I solved the button click to update issue, the D3 javascript is now appending one chart per button click, resulting in duplicate charts instead of simply updating the data.

我理解点击事件调用 append()在D3代码中每次触发,但是如何解决这个问题,所以只有一个图表更新的数据每次点击?

I understand that the click event is calling append() in the D3 code every time it is triggered, but how can I get around this so there's only one chart with updated data per click?

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

});


推荐答案

要处理创建和更新,如何写 draw 函数。

To handle creation and updates, you will have to reorganize how the draw function is written.

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

classic enter-update-exit 模式在这篇有关制作可重复使用的文章图表。这个答案很大程度上取决于这种模式。

This classical enter-update-exit pattern is improved upon in this article on making reusable graphs. This answer draws heavily on that pattern.

使用closures的一个更好的实现,你将能够节省每次浪费在初始化上的几个CPU周期。

With a slightly better implementation which uses closures, you will be able to save the few CPU cycles wasted on initialization each time.

这篇关于更新D3图表,导致重复图表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆