且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在d3.js v4中绘制滚动/移动平均值

更新时间:2022-12-20 07:53:07

另一个答案是真的很好,可能***的方式来实现你的目标,但是对于后代,这里是新的d3形状的n移动平均 curve factory 方法:

The other answer is really good and is probably the best way to achieve your aims. But for posterity's sake, here's a n-moving-average in the new d3-shape curve factory methodology:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  <script>
    function NMoveAvg(context, N) {
      this._context = context;
      this._points = {
        x: [],
        y: []
      };
      this._N = N;
    }

    NMoveAvg.prototype = {
      areaStart: function() {
        this._line = 0;
      },
      areaEnd: function() {
        this._line = NaN;
      },
      lineStart: function() {
        this._point = 0;
      },
      lineEnd: function() {
        if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
        this._line = 1 - this._line;
      },
      point: function(x, y) {
        x = +x, y = +y;

        this._points.x.push(x);
        this._points.y.push(y);

        if (this._points.x.length < this._N) return;

        var aX = this._points.x.reduce(function(a, b) {
            return a + b;
          }, 0) / this._N,
          aY = this._points.y.reduce(function(a, b) {
            return a + b;
          }, 0) / this._N;

        this._points.x.shift();
        this._points.y.shift();

        switch (this._point) {
          case 0:
            this._point = 1;
            this._line ? this._context.lineTo(aX, aY) : this._context.moveTo(aX, aY);
            break;
          case 1:
            this._point = 2; // proceed
          default:
            this._context.lineTo(aX, aY);
            break;
        }
      }
    };

    var curveNMoveAge = (function custom(N) {

      function nMoveAge(context) {
        return new NMoveAvg(context, N);
      }

      nMoveAge.N = function(N) {
        return custom(+N);
      };

      return nMoveAge;
    })(0);
  </script>
</head>

<body>
  <script>
    var data = [3, 66, 2, 76, 5, 20, 1, 30, 50, 9, 80, 5, 7];

    var w = 500,
      h = 500;

    var x = d3.scaleLinear()
      .domain([0, 12])
      .range([0, w]);

    var y = d3.scaleLinear()
      .domain([0, 100])
      .range([0, h]);

    var svg = d3.select("body")
      .append("svg")
      .attr("width", w)
      .attr("height", h);


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

    svg.append("path")
      .datum(data)
      .attr("d", line.curve(curveNMoveAge.N(3)))
      .style("fill", "none")
      .style("stroke", "steelblue");

    svg.append("path")
      .datum(data)
      .attr("d", line.curve(d3.curveLinear))
      .style("fill", "none")
      .style("stroke", "black");
  </script>
</body>

</html>