D3.JS V4在添加/更新数据后更新图表元素

时间:2018-03-13 14:10:32

标签: javascript d3.js

我正在尝试使用d3.js V4构建简单的折线图。 我有多个bl.ocks样本的基本概念。

我的想法是创建char然后向其添加数据,最多9个数据点。

以下是我迄今为止构建的内容:

enter image description here

我可以使用此更新行:

addValue: function(val) {
    chartData.push(val);

    if (chartData.length > 9) {
        chartData.shift();
    }

    y.domain([
    -2,
    d3.max(chartData, function(d) {
      return d + 2;
    })
    ]);

    var svg = element.transition();
    svg
    .select(".d3-line")
    .duration(750)
    .attr("d", valueline(chartData));
}

但是当我添加新数据时我还想添加/移动点和线,没有这个我的错误图表看起来像这样:

enter image description here

我正在使用此代码添加初始点和行:

var lineGuides = svg
  .append("g")
  .selectAll(".d3-line-guides-group")
  .data(chartData);

lineGuides
  .enter()
  .append("line")
  .attr("class", "d3-line-guides")
  .attr("x1", function(t, e) {
    return x(e);
  })
  .attr("y1", function(t, a) {
    return height;
  })
  .attr("x2", function(t, e) {
    return x(e);
  })
  .attr("y2", function(t, a) {
    return height;
  })
  .style("stroke", "rgba(255,255,255,0.3)")
  .style("stroke-dasharray", "4,2")
  .style("shape-rendering", "crispEdges")
  .transition()
  .duration(1000)
  .delay(function(t, x) {
    return 150 * x;
  })
  .attr("y2", function(t) {
    return y(t);
  })
  .transition();

var points = svg
  .insert("g")
  .selectAll(".d3-line-circle")
  .data(chartData)
  .enter()
  .append("circle")
  .attr("class", "d3-line-circle d3-line-circle-medium")
  .attr("cx", function(t, e) {
    return x(e);
  })
  .attr("cy", function(t) {
    return y(t);
  })
  .attr("r", 3)
  .style("stroke", "#fff")
  .style("fill", "#29B6F6")
  .on("mouseover", function(t) {
    d3
      .select(this)
      .transition()
      .duration(250)
      .attr("r", 5);
  })
  .on("mouseout", function(t) {
    d3
      .select(this)
      .transition()
      .duration(250)
      .attr("r", 3);
  });
points
  .style("opacity", 0)
  .transition()
  .duration(250)
  .ease(d3.easeLinear, 2)
  .delay(1000)
  .style("opacity", 1);

如何在数据更改时添加新点并更新旧点?

这是我到目前为止的代码:

/* global window, define, module */
(function(global, factory) {
  var MicroChart = factory(global);
  if (typeof define === "function" && define.amd) {
    // AMD support
    define(function() {
      return MicroChart;
    });
  } else if (typeof module === "object" && module.exports) {
    // CommonJS support
    module.exports = MicroChart;
  } else {
    // We are probably running in the browser
    global.MicroChart = MicroChart;
  }
})(typeof window === "undefined" ? this : window, function(global, undefined) {
  var document = global.document;
  var slice = Array.prototype.slice;

  var MicroChart = (function() {
    var defaultOptions = {
      height: 50
    };

    function shallowCopy(/* source, ...targets*/) {
      var target = arguments[0],
        sources = slice.call(arguments, 1);
      sources.forEach(function(s) {
        for (k in s) {
          if (s.hasOwnProperty(k)) {
            target[k] = s[k];
          }
        }
      });
      return target;
    }

    return function MicroChart(elem, opts) {
      opts = shallowCopy({}, defaultOptions, opts);
      var gaugeContainer = elem,
        chartHeigh = opts.height,
        instance;

      var xScale, yScale, valueline, x, y;
      var chartData = [5, 8, 2];
      var element;


      function initializeMicroChart(elem, height) {
        element = d3.select(elem);

        var margins = { top: 0, right: 0, bottom: 0, left: 0 };
        var width =
          element.node().getBoundingClientRect().width -
          margins.left -
          margins.right;
        var height = chartHeigh - margins.top - margins.bottom;

        var l = 10;

        x = d3
          .scaleLinear()
          .domain([0, 8])
          .range([l, width - l]);

        y = d3.scaleLinear().range([height, 0]);

        valueline = d3
          .line()
          .x(function(d, i) {
            console.log(i);
            return x(i);
          })
          .y(function(d) {
            return y(d);
          });

        var svg = element
          .append("svg")
          .attr("width", width + margins.left + margins.right)
          .attr("height", height + margins.top + margins.bottom);

        y.domain([
          -2,
          d3.max(chartData, function(d) {
            return d + 2;
          })
        ]);


      var s4 =function() {
        return Math.floor((1 + Math.random()) * 0x10000)
          .toString(16)
          .substring(1);
      }


        var guid = s4()+s4();
        console.log(guid);

        var path = svg
          .append("path")
          .data([chartData])
          .attr("class", "d3-line d3-line-medium")
          .attr("clip-path", "url(#"+guid+")")
          .attr("d", valueline)
          .style("stroke", "#fff");

        var clipPath = svg
          .append("defs")
          .append("clipPath")
          .attr("id", guid);

        var rect = clipPath
          .append("rect")
          .attr("class", "clip")
          .attr("width", 0)
          .attr("height", height)
          .attr("transform", null)
          .transition()
          .duration(1000)
          .ease(d3.easeLinear, 2)
          .attr("width", width);

        var lineGuides = svg
          .append("g")
          .selectAll(".d3-line-guides-group")
          .data(chartData);

        lineGuides
          .enter()
          .append("line")
          .attr("class", "d3-line-guides")
          .attr("x1", function(t, e) {
            return x(e);
          })
          .attr("y1", function(t, a) {
            return height;
          })
          .attr("x2", function(t, e) {
            return x(e);
          })
          .attr("y2", function(t, a) {
            return height;
          })
          .style("stroke", "rgba(255,255,255,0.3)")
          .style("stroke-dasharray", "4,2")
          .style("shape-rendering", "crispEdges")
          .transition()
          .duration(1000)
          .delay(function(t, x) {
            return 150 * x;
          })
          .attr("y2", function(t) {
            return y(t);
          })
          .transition();

        var points = svg
          .insert("g")
          .selectAll(".d3-line-circle")
          .data(chartData)
          .enter()
          .append("circle")
          .attr("class", "d3-line-circle d3-line-circle-medium")
          .attr("cx", function(t, e) {
            return x(e);
          })
          .attr("cy", function(t) {
            return y(t);
          })
          .attr("r", 3)
          .style("stroke", "#fff")
          .style("fill", "#29B6F6")
          .on("mouseover", function(t) {
            d3
              .select(this)
              .transition()
              .duration(250)
              .attr("r", 5);
          })
          .on("mouseout", function(t) {
            d3
              .select(this)
              .transition()
              .duration(250)
              .attr("r", 3);
          });
        points
          .style("opacity", 0)
          .transition()
          .duration(250)
          .ease(d3.easeLinear, 2)
          .delay(1000)
          .style("opacity", 1);
      }
      instance = {
        addValue: function(val) {
          chartData.push(val);

          if (chartData.length > 9) {
            chartData.shift();
          }

          y.domain([
            -2,
            d3.max(chartData, function(d) {
              return d + 2;
            })
          ]);

          var svg = element.transition();
          svg
            .select(".d3-line")
            .duration(750)
            .attr("d", valueline(chartData));
        }
      };

      initializeMicroChart(gaugeContainer, chartHeigh);
      return instance;
    };
  })();

  return MicroChart;
});

var gauge1 = MicroChart(document.getElementById("chart1"));

var gauge2 = MicroChart(document.getElementById("chart2"), {
  height: 70
});

var randomInt = function(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

$("#update").on("click", function() {
  gauge1.addValue(randomInt(5, 15));
  gauge2.addValue(randomInt(5, 15));
});

以下是代码,以查看我的代码:https://codepen.io/Misiu/pen/dmGyZW?editors=0010

1 个答案:

答案 0 :(得分:2)

使用.enter().append()添加新节点.merge()以合并现有节点和附加节点,然后更新所有节点并调用.exit().remove()以删除不必要的节点。因此,您可以使用以下更新模式:

d3.select(window).on('load', function() {
  // Join data
  var joined = d3.select('div').selectAll('p').data([1, 2, 3, 4, 5]);
  joined
  // Add new elements
    .enter().append('p')
  // Merge both new and existing elements 
    .merge(joined)
  // Update new and existing elements 
    .text(d => d);
  // Remove excess elements
  joined.exit().remove();
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<div>
  <p>a</p>
  <p>b</p>
  <p>c</p>
</div>

结果,将创建两个<p>元素,并且将更新所有<p>元素。

另见General Update Pattern, I