D3使用新数据集更新条形图会导致更新问题

时间:2014-03-05 21:51:24

标签: javascript d3.js bar-chart

使用默认的给定数据,条形图的渲染效果很好。单击按钮时会出现问题,这也会导致获取新数据集。更新x轴y轴效果很好,但渲染数据会导致问题。

首先尝试删除之前添加的所有rects,然后添加新数据集。但是所有新的rect元素都被添加到了错误的位置,因为没有对旧版本的引用。

这是代码,重绘在代码的末尾。

http://jsfiddle.net/staar2/wBNWK/9/

 var data = JSON.parse('[{"hour":0,"time":147},{"hour":1,"time":0},{"hour":2,"time":74},{"hour":3,"time":141},{"hour":4,"time":137},{"hour":5,"time":210},{"hour":6,"time":71},{"hour":7,"time":73},{"hour":8,"time":0},{"hour":9,"time":68},{"hour":10,"time":70},{"hour":11,"time":0},{"hour":12,"time":147},{"hour":13,"time":0},{"hour":14,"time":0},{"hour":15,"time":69},{"hour":16,"time":67},{"hour":17,"time":67},{"hour":18,"time":66},{"hour":19,"time":0},{"hour":20,"time":0},{"hour":21,"time":66},{"hour":22,"time":210},{"hour":23,"time":0}] ');

  var w = 15,
      h = 80;

  var xScale = d3.scale.linear()
      .domain([0, 1])
      .range([0, w]);

  var yScale = d3.scale.linear()
      .domain([0, d3.max(data, function (d) {
          return d.time;
      })])
      .rangeRound([5, h]);

  var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom")
      .ticks(5);

  var yAxis = d3.svg.axis()
      .scale(yScale)
      .orient("left");

  var chart = d3.select("#viz")
    .append("svg")
    .attr("class", "chart")
    .attr("width", w * data.length - 1)
    .attr("height", h);

  chart.selectAll("rect")
    .data(data)
    .enter().append("rect")
    .attr("x", function(d, i) {
      return xScale(i) - 0.5;
    })
    .attr("y", function(d) {
      return h - yScale(d.time) - 0.5;
    })
    .attr("width", w)
    .attr("height", function(d) {
      return yScale(d.time);
    });

  chart.selectAll("text")
   .data(data)
   .enter()
   .append("text")
   .text(function(d) {
      if (d.time > 10) {
        return Math.round(d.time);
      }
   })
   .attr("font-family", "sans-serif")
   .attr("font-size", "11px")
   .attr("fill", "#FFF")
   .attr("text-anchor", "middle")
   .attr("x", function(d, i) {
        return xScale(i) + w / 2;
   })
   .attr("y", function(d) {
        return h - yScale(d.time) - 0.5 + 10;
   });

  chart.append("g")
    .attr("transform", "translate(0," + (h) + ")")
    .call(xAxis);

    function redraw() {

      // This the part where the incoming data set also changes, which means the update to x-axis y-axis, labels

      yScale.domain([0, d3.max(data, function (d) {
        return d.time;
      })]);

      var bars = d3.selectAll("rect")
        .data(data, function (d) {
           return d.hour;
        });

      bars
         .transition()
         .duration(500)
         .attr("x", w)  // <-- Exit stage left
         .remove();

      d3.selectAll("rect") // This is actually empty
        .data(data, function (d) {
          return d.hour;
        })
        .enter()
        .append("rect")
        .attr("x", function(d, i) {
          console.log(d, d.day, xScale(d.day));

          return xScale(d.day);
        })
        .attr("y", function(d) {
          return yScale(d.time);
        })
        .attr("width", w)
        .attr("height", function (d) {
          return h - yScale(d.time);
        });
    }

    d3.select("button").on("click", function() {
      console.log('Clicked');

      redraw();
    });

2 个答案:

答案 0 :(得分:1)

同意Sam(虽然还有一些问题,比如使用remove()而不使用exit()等)并且我正在推出它,因为我正在玩它,因为我正在清理代码并应用更新图案。以下是FIDDLE,其中包含我的代码更改。我只更改了前几个数据点,但这应该可以帮助你。

var data2 = JSON.parse('[{"hour":0,"time":153},{"hour":1,"time":10},{"hour":2,"time":35},{"hour":3,"time":150},

更新:根据请求,添加逻辑以考虑使用新数据进行更新。 UPDATED FIDDLE

答案 1 :(得分:0)

由于您将相同的数据绑定到bars,因此enter选项为空。删除现有小节后,append选择中的每个数据点都会enter一个新小节 - 这也是空的。如果您有不同的数据,则应附加条形图。

如果您还没有仔细阅读,general update pattern是了解此类事情的绝佳资源。