javascript - d3月度数据集-更新数据-添加新组

标签 javascript d3.js

我正在研究个人财务的可视化,以学习 d3,感觉像是一个有用的项目。我已经设法按照我的意愿制作每个月的图表(每天+或减去)。现在我希望能够从一个月更改为下一个月。如果旧月份(更新前)的天数(又名数据点)比新月份(更新后)多,则此方法有效。如果旧数据点少于新数据点,则会在图表顶部添加额外的数据点。我将条形图中的每个数据点作为一个组添加(条形图本身、数据标签 + 日期标签)。我正在为每个新的一天向下翻译整个小组。我需要弄清楚的是,更新后我的数据点是多了还是少了,如果少了,我需要向下翻译新的数据点。 你知道我的意思? 这是我最初添加条形图的代码:

bar = chart.selectAll("g")
      .data(data)
      .enter().append("g")
      .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
    //bar


//grey background bars 
  bar.append("rect")
          .attr("class", "backgroundBar")
          .attr("x", 10)
          .attr("width", (width-30))
          .attr("height", barHeight-1)
          .attr("fill", "#dddddd")
          .attr("fill-opacity", "0.3");

  //dateLabel
  bar.append("text")
        .attr("class", "dateLabel")
        .attr("x", width/2-20)
        .attr("y", barHeight-5)
       .attr("fill", "black")
        .text(function(d){ return d.key})
  bar.append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
          .attr("width", function(d) { return Math.abs(scale(d.values.total)); })
          .attr("height", barHeight - 1)
          .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});
  //BarLabel
  bar.append("text")
        .attr("class", "barLabel")
        .attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
        .attr("y", barHeight/2)
        .attr("dy", ".35em")
        .attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
        .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
        .text(function(d) { return Math.round(d.values.total*100)/100; });

我显然不能与组一起工作,而是平移每个 y 坐标,但这感觉像是一个肮脏的解决方案,不是吗? 这是问题的屏幕截图:enter image description here

编辑: 这是我当前的更新功能。有点像,但会在屏幕截图中产生结果

//update the bar itself


var bar=chartgroups.selectAll(".bar")
          .data(data);
  bar.enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
          .attr("width", function(d) { return Math.abs(scale(d.values.total)); })
          .attr("height", barHeight - 1)
          .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});
  bar.exit().remove();
  bar
    .transition().duration(750)
      .attr("height", barHeight - 1)
      .attr("x", function(d) { if(scale(d.values.total)<0){return width/2+widthDateLabel;}else{return width/2-scale(d.values.total)-widthDateLabel;}})
      .attr("width", function(d) { return Math.abs(scale(d.values.total)); })
      .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}});

  //update the barLabel
  var barLabel=chart.selectAll(".barLabel").data(data);
  barLabel.enter().append("text")
        .attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
        .attr("y", barHeight/2)
        .attr("dy", ".35em")
        .attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
        .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
        .text(function(d) { return Math.round(d.values.total*100)/100; });
  barLabel.exit().remove();
  barLabel
    .transition().duration(750)
      .attr("x",function(d) { if(scale(d.values.total)<0){return window.width/2-scale(d.values.total)+5+widthDateLabel;}else{return window.width/2-scale(d.values.total)-5-widthDateLabel;}})
      .attr("y", barHeight/2)
      .attr("text-anchor", function(d) { if(scale(d.values.total)<0){ return "start"}else{return "end"}})
      .attr("fill", function(d) { if(scale(d.values.total)<0){ return "DeepPink"}else{return "MediumSeaGreen"}})
      .text(function(d) { return Math.round(d.values.total*100)/100; });

  //update dates
  var dateLabel=chart.selectAll(".dateLabel").data(data);
  dateLabel.enter().append("text")
        .attr("class", "dateLabel")
        .attr("x", width/2-20)
        .attr("y", barHeight-5)
        .attr("fill", "black")
        .text(function(d){ return d.key})
  dateLabel.exit().remove();
  dateLabel
    .transition().duration(750)
        .text(function(d){ return d.key})
        .attr("y", barHeight-5)

  //update background bars
  var backgroundBar=chart.selectAll(".backgroundBar").data(data);
  backgroundBar.enter().append("rect")
          .attr("class", "backgroundBar")
          .attr("x", 10)
          .attr("width", (width-30))
          .attr("height", barHeight-1)
          .attr("fill", "#dddddd")
          .attr("fill-opacity", "0.3");
  backgroundBar.exit().remove();
  backgroundBar
    .transition().duration(750)
      .attr("height", barHeight-1)

最佳答案

这是一个工作代码片段,当您按下按钮时,它会在两个月之间转换。它非常接近您的代码。只是更新发生方式的细微差别。

var january = [
    { "day": "1/1/2015", "value": 105},
    { "day": "1/2/2015", "value": -119},
    { "day": "1/3/2015", "value": 148},
    { "day": "1/4/2015", "value": -161},
    { "day": "1/5/2015", "value": 142},
    { "day": "1/6/2015", "value": -105},
    { "day": "1/7/2015", "value": 131},
    { "day": "1/8/2015", "value": 42},
    { "day": "1/9/2015", "value": -74},
    { "day": "1/10/2015", "value": 175},
    { "day": "1/11/2015", "value": 154},
    { "day": "1/12/2015", "value": 164},
    { "day": "1/13/2015", "value": 31},
    { "day": "1/14/2015", "value": 81},
    { "day": "1/15/2015", "value": 5},
    { "day": "1/16/2015", "value": -194},
    { "day": "1/17/2015", "value": -90},
    { "day": "1/18/2015", "value": 8},
    { "day": "1/19/2015", "value": 161},
    { "day": "1/20/2015", "value": -99},
    { "day": "1/21/2015", "value": -42},
    { "day": "1/22/2015", "value": -145},
    { "day": "1/23/2015", "value": 168},
    { "day": "1/24/2015", "value": -44},
    { "day": "1/25/2015", "value": -2},
    { "day": "1/26/2015", "value": 177},
    { "day": "1/27/2015", "value": -21},
    { "day": "1/28/2015", "value": -29},
    { "day": "1/29/2015", "value": 192},
    { "day": "1/30/2015", "value": 199},
    { "day": "1/31/2015", "value": 79}
  ];

  var february = [
    {    "day": "2/1/2015", "value": "36"},
    {    "day": "2/2/2015", "value": "151"},
    {    "day": "2/3/2015", "value": "-157"},
    {    "day": "2/4/2015", "value": "39"},
    {    "day": "2/5/2015", "value": "-69"},
    {    "day": "2/6/2015", "value": "97"},
    {    "day": "2/7/2015", "value": "-55"},
    {    "day": "2/8/2015", "value": "156"},
    {    "day": "2/9/2015", "value": "151"},
    {    "day": "2/10/2015", "value": "-72"},
    {    "day": "2/11/2015", "value": "-17"},
    {    "day": "2/12/2015", "value": "154"},
    {    "day": "2/13/2015", "value": "77"},
    {    "day": "2/14/2015", "value": "80"},
    {    "day": "2/15/2015", "value": "-112"},
    {    "day": "2/16/2015", "value": "-155"},
    {    "day": "2/17/2015", "value": "21"},
    {    "day": "2/18/2015", "value": "-63"},
    {    "day": "2/19/2015", "value": "-136"},
    {    "day": "2/20/2015", "value": "127"},
    {    "day": "2/21/2015", "value": "-43"},
    {    "day": "2/22/2015", "value": "-66"},
    {    "day": "2/23/2015", "value": "105"},
    {    "day": "2/24/2015", "value": "2"},
    {    "day": "2/25/2015", "value": "-92"},
    {    "day": "2/26/2015", "value": "-160"},
    {    "day": "2/27/2015", "value": "13"},
    {    "day": "2/28/2015", "value": "163"}
  ];

  function updateData(data) {

    var maxValue = d3.max(data, function(d) { return Math.abs(d.value); });
    scaleX.domain([0, maxValue]);

    //update background bars
    var backgroundBar = chartgroups.selectAll(".backgroundBar").data(data);
    backgroundBar.enter().append("rect");
    backgroundBar.attr("class", "backgroundBar")
      .attr("x", 0 - margin)
      .attr("y", function (d, i) {
        return (i * barHeight);
      })
      .attr("width", chartWidth*2 + margin)
      .attr("height", barHeight - 1)
      .attr("fill", "#dddddd")
      .attr("fill-opacity", "0.3");
    backgroundBar.exit().remove();

    var bars = chartgroups.selectAll(".bar")
      .data(data);
    bars.enter().append("rect")
      .attr("fill", function (d) {
        if (d.value < 0) {
          return "DeepPink"
        } else {
          return "MediumSeaGreen"
        }
      });
    bars.attr("class", "bar")
      .transition()
      .duration(1000)
      .attr("x", function (d) {
        if (d.value < 0) {
          return negativeStart;
        } else {
          return scaleWidth - scaleX(d.value);
        }
      }).attr("y", function (d, i) {
        return i * barHeight;
      })
      .attr("width", function (d) {
        return scaleX(Math.abs(d.value));
      })
      .attr("height", barHeight - 1)
      .attr("fill", function (d) {
        if (d.value < 0) {
          return "DeepPink"
        } else {
          return "MediumSeaGreen"
        }
      });
    bars.exit().remove();

    //update the barLabel
    var barLabel = chartgroups.selectAll(".barLabel").data(data);
    barLabel.enter().append("text");
    barLabel.attr("class", "barLabel")
      .transition()
      .duration(1000)
      .attr("x", function (d) {
        if (d.value < 0) {
          return negativeStart + scaleX(Math.abs(d.value));
        } else {
          return scaleWidth - scaleX(d.value);
        }
      })
      .attr("y", function (d, i) {
        return (i * barHeight) + (barHeight/2);
      })
      .attr("dy", ".35em")
      .attr("text-anchor", function (d) {
        if (d.value < 0) {
          return "start"
        } else {
          return "end"
        }
      })
      .attr("fill", function (d) {
        if (d.value < 0) {
          return "DeepPink"
        } else {
          return "MediumSeaGreen"
        }
      })
      .text(function (d) {
        return Math.round(d.value * 100) / 100;
      });
    barLabel.exit().remove();

    // //update dates
    var dateLabel = chartgroups.selectAll(".dateLabel").data(data);
    dateLabel.enter().append("text");
    dateLabel.attr("class", "dateLabel")
      .attr("fill", "black")
      .transition()
      .duration(1000)
      .attr("x", scaleWidth)
      .attr("y", function (d, i) {
        return (i * barHeight) + (barHeight/2) + 1;
      })
      .text(function (d) {
        return d.day;
      });
    dateLabel.exit().remove();
  }

  var container = d3.select(".chart");
  var margin = 60;
  var containerWidth = container.node().getBoundingClientRect().width;
  var chartWidth = containerWidth - (2*margin);
  var barHeight = 20;
  var dateLabelWidth = 80;
  var chartHeight = 31 * barHeight;
  var scaleWidth = (chartWidth - dateLabelWidth) / 2;
  var negativeStart = chartWidth - scaleWidth;
  var scaleX = d3.scale.linear()
    .range([0, scaleWidth]);
  var chartgroups = container.append("svg")
    .attr("width", containerWidth)
    .attr("height", chartHeight)
    .append("g")
    .attr("transform", "translate(" + margin + "," + 0 + ")");

  updateData(january);

  d3.select(".january").on("click", function() {
    updateData(january);
  });
  d3.select(".february").on("click", function() {
    updateData(february);
  });
.chart {
      width: 100%;
    }
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
</head>
<body>
<button type="button" class="january">January</button>
<button type="button" class="february">February</button>
<div class="chart">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</body>
</html>

通常负数会在左边。您也可以使用 y 比例尺,并且可能有更简洁的方法来创建 x 比例尺。

关于javascript - d3月度数据集-更新数据-添加新组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36518131/

相关文章:

javascript - D3 4.0 rangeRoundBands 等效?

javascript - d3.js - 过渡仅在没有 svg 标题的情况下开始,而不是从它开始

javascript - d3.js 数据丢失,我该如何解决?

javascript - Nodejs 对象声明和立即速记 if 语句使应用程序崩溃

javascript - 有没有办法让 CSS 动画在动画对象不可见之前不运行?

javascript - 如何让 DIV 占据容器 div 的其余高度?

javascript - jQuery 中指示表单完成的进度条

javascript - 在 Leaflet/Mapbox map 上绘制 d3 图表

javascript - Angular 和 D3.js : Why is element[0] undefined?

javascript - 使用 JavaScript/ajax 在单击按钮上更改特定 TD 的背景颜色