【问题标题】:Clear and Redraw data on Line Chart using Canvas使用 Canvas 清除和重绘折线图上的数据
【发布时间】:2015-12-05 14:07:59
【问题描述】:

我正在使用带有 Canvas 的折线图。我用我得到的数据作画。 yValue 显示数据,xValue 像动态折线图一样随着 updateInterval 时间增加一步。我想在xValue >= 200时清除折线图上绘制的数据并重新绘制新数据。我该如何解决这个问题?

非常感谢。

<html>
<head>
</head>
<body>
    <canvas id="myCanvas" width="1200" height="600" style="border:1px solid black;"></canvas>
    <script type="text/javascript">
    function LineChart(config){
    // user defined properties
    this.canvas = document.getElementById(config.canvasId);
    this.minX = config.minX;
    this.minY = config.minY;
    this.maxX = config.maxX;
    this.maxY = config.maxY;
    this.unitsPerTickX = config.unitsPerTickX;
    this.unitsPerTickY = config.unitsPerTickY;
    // constants
    this.padding = 10;
    this.tickSize = 10;
    this.axisColor = "#555";
    this.pointRadius = 2;
    this.font = "12pt Calibri";
    /*
    * measureText does not provide a text height
    * metric, so we'll have to hardcode a text height
    * value
    */
    this.fontHeight = 12;
    // relationships
    this.context = this.canvas.getContext("2d");
    this.rangeX = this.maxX - this.minY;
    this.rangeY = this.maxY - this.minY;
    this.numXTicks = Math.round(this.rangeX / this.unitsPerTickX);
    this.numYTicks = Math.round(this.rangeY / this.unitsPerTickY);
    this.x = this.getLongestValueWidth() + this.padding * 2;
    this.y = this.padding * 2;
    this.width = this.canvas.width - this.x - this.padding * 2;
    this.height = this.canvas.height - this.y - this.padding -
    this.fontHeight;
    this.scaleX = this.width / this.rangeX;
    this.scaleY = this.height / this.rangeY;
    // draw x y axis and tick marks
    this.drawXAxis();
    this.drawYAxis();
    }
    LineChart.prototype.getLongestValueWidth = function(){
    this.context.font = this.font;
    var longestValueWidth = 0;
    for (var n = 0; n <= this.numYTicks; n++) {
    var value = this.maxY - (n * this.unitsPerTickY);
    longestValueWidth = Math.max(longestValueWidth, this.
    context.measureText(value).width);
    }
    return longestValueWidth;
    };
    LineChart.prototype.drawXAxis = function(){
    var context = this.context;
    context.save();
    context.beginPath();
    context.moveTo(this.x, this.y + this.height);
    context.lineTo(this.x + this.width, this.y + this.height);
    context.strokeStyle = this.axisColor;
    context.lineWidth = 2;
    context.stroke();
    // draw tick marks
    for (var n = 0; n < this.numXTicks; n++) {
    context.beginPath();
    context.moveTo((n + 1) * this.width / this.numXTicks +
    this.x, this.y + this.height);
    context.lineTo((n + 1) * this.width / this.numXTicks +
    this.x, this.y + this.height - this.tickSize);
    context.stroke();
    }
    // draw labels
    context.font = this.font;
    context.fillStyle = "black";
    context.textAlign = "center";
    context.textBaseline = "middle";
    for (var n = 0; n < this.numXTicks; n++) {
    var label = Math.round((n + 1) * this.maxX / this.
    numXTicks);
    context.save();
    context.translate((n + 1) * this.width / this.numXTicks +
    this.x, this.y + this.height + this.padding);
    context.fillText(label, 0, 0);
    context.restore();
    }
    context.restore();
    };
    LineChart.prototype.drawYAxis = function(){
    var context = this.context;
    context.save();
    context.save();
    context.beginPath();
    context.moveTo(this.x, this.y);
    context.lineTo(this.x, this.y + this.height);
    context.strokeStyle = this.axisColor;
    context.lineWidth = 2;
    context.stroke();
    context.restore();
    // draw tick marks
    for (var n = 0; n < this.numYTicks; n++) {
    context.beginPath();
    context.moveTo(this.x, n * this.height / this.numYTicks +
    this.y);
    context.lineTo(this.x + this.tickSize, n * this.height /
    this.numYTicks + this.y);
    context.stroke();
        }
    // draw values
    context.font = this.font;
    context.fillStyle = "black";
    context.textAlign = "right";
    context.textBaseline = "middle";
    for (var n = 0; n < this.numYTicks; n++) {
    var value = Math.round(this.maxY - n * this.maxY / this.numYTicks);
    context.save();
    context.translate(this.x - this.padding, n * this.height /
    this.numYTicks + this.y);
    context.fillText(value, 0, 0);
    context.restore();
    }
    context.restore();
    };
    LineChart.prototype.drawLine = function(data, color, width){
    var context = this.context;
    context.save();
    this.transformContext();
    context.lineWidth = width;
    context.strokeStyle = color;
    context.fillStyle = color;
    context.beginPath();
    context.moveTo(data[0].x * this.scaleX, data[0].y * this.
    scaleY);
    for (var n = 0; n < data.length; n++) {
    var point = data[n];
    // draw segment
    context.lineTo(point.x * this.scaleX, point.y * this.
    scaleY);
    context.stroke();
    context.closePath();
    context.beginPath();
    context.arc(point.x * this.scaleX, point.y * this.scaleY,
    this.pointRadius, 0, 2 * Math.PI, false);
    context.fill();
    context.closePath();
    // position for next segment
    context.beginPath();
    context.moveTo(point.x * this.scaleX, point.y * this.scaleY);
    }
    context.restore();
    };
    LineChart.prototype.transformContext = function(){
    var context = this.context;
    // move context to center of canvas
    this.context.translate(this.x, this.y + this.height);
    // invert the y scale so that that increments
    // as you move upwards
    context.scale(1, -1);
    };
    window.onload = function(){
    var myLineChart = new LineChart({
    canvasId: "myCanvas",
    minX: 0,
    minY: 0,
    maxX: 200,
    maxY: 260,
    unitsPerTickX: 20,
    unitsPerTickY: 50
    });
    var dps = [];
    var xVal = dps.length + 1;
    var yVal ;
    var updateInterval = 100;
    function updatedata(){
    yVal = xVal;
    dps.push({x: xVal,y: yVal});
    xVal++;
    myLineChart.drawLine(dps, "blue", 3);       
    };
    setInterval(function(){updatedata()}, updateInterval); 
    };
    </script>
    </body>
    </html>

【问题讨论】:

    标签: javascript html canvas html5-canvas linechart


    【解决方案1】:

    要重新设置同一行的动画,只需清除 dps 并重置 xVal

    在您的updatedata 函数中,测试是否为xVal&gt;200。如果是:

    • 清除画布
    • 重绘 X 和 Y 轴
    • dps 数组重置为零长度
    • xVal重置为dps.length+1

    这是示例代码和演示:

    function LineChart(config){
      // user defined properties
      this.canvas = document.getElementById(config.canvasId);
      this.minX = config.minX;
      this.minY = config.minY;
      this.maxX = config.maxX;
      this.maxY = config.maxY;
      this.unitsPerTickX = config.unitsPerTickX;
      this.unitsPerTickY = config.unitsPerTickY;
      // constants
      this.padding = 10;
      this.tickSize = 10;
      this.axisColor = "#555";
      this.pointRadius = 2;
      this.font = "12pt Calibri";
      /*
            * measureText does not provide a text height
            * metric, so we'll have to hardcode a text height
            * value
            */
      this.fontHeight = 12;
      // relationships
      this.context = this.canvas.getContext("2d");
      this.rangeX = this.maxX - this.minY;
      this.rangeY = this.maxY - this.minY;
      this.numXTicks = Math.round(this.rangeX / this.unitsPerTickX);
      this.numYTicks = Math.round(this.rangeY / this.unitsPerTickY);
      this.x = this.getLongestValueWidth() + this.padding * 2;
      this.y = this.padding * 2;
      this.width = this.canvas.width - this.x - this.padding * 2;
      this.height = this.canvas.height - this.y - this.padding -
        this.fontHeight;
      this.scaleX = this.width / this.rangeX;
      this.scaleY = this.height / this.rangeY;
      // draw x y axis and tick marks
      this.drawXAxis();
      this.drawYAxis();
    }
    LineChart.prototype.getLongestValueWidth = function(){
      this.context.font = this.font;
      var longestValueWidth = 0;
      for (var n = 0; n <= this.numYTicks; n++) {
        var value = this.maxY - (n * this.unitsPerTickY);
        longestValueWidth = Math.max(longestValueWidth, this.
                                     context.measureText(value).width);
      }
      return longestValueWidth;
    };
    //
    LineChart.prototype.drawXAxis = function(){
      var context = this.context;
      context.save();
      context.beginPath();
      context.moveTo(this.x, this.y + this.height);
      context.lineTo(this.x + this.width, this.y + this.height);
      context.strokeStyle = this.axisColor;
      context.lineWidth = 2;
      context.stroke();
      // draw tick marks
      for (var n = 0; n < this.numXTicks; n++) {
        context.beginPath();
        context.moveTo((n + 1) * this.width / this.numXTicks +
                       this.x, this.y + this.height);
        context.lineTo((n + 1) * this.width / this.numXTicks +
                       this.x, this.y + this.height - this.tickSize);
        context.stroke();
      }
      // draw labels
      context.font = this.font;
      context.fillStyle = "black";
      context.textAlign = "center";
      context.textBaseline = "middle";
      for (var n = 0; n < this.numXTicks; n++) {
        var label = Math.round((n + 1) * this.maxX / this.
                               numXTicks);
        context.save();
        context.translate((n + 1) * this.width / this.numXTicks +
                          this.x, this.y + this.height + this.padding);
        context.fillText(label, 0, 0);
        context.restore();
      }
      context.restore();
    };
    //
    LineChart.prototype.drawYAxis = function(){
      var context = this.context;
      context.save();
      context.save();
      context.beginPath();
      context.moveTo(this.x, this.y);
      context.lineTo(this.x, this.y + this.height);
      context.strokeStyle = this.axisColor;
      context.lineWidth = 2;
      context.stroke();
      context.restore();
      // draw tick marks
      for (var n = 0; n < this.numYTicks; n++) {
        context.beginPath();
        context.moveTo(this.x, n * this.height / this.numYTicks +
                       this.y);
        context.lineTo(this.x + this.tickSize, n * this.height /
                       this.numYTicks + this.y);
        context.stroke();
      }
      // draw values
      context.font = this.font;
      context.fillStyle = "black";
      context.textAlign = "right";
      context.textBaseline = "middle";
      for (var n = 0; n < this.numYTicks; n++) {
        var value = Math.round(this.maxY - n * this.maxY / this.numYTicks);
        context.save();
        context.translate(this.x - this.padding, n * this.height /
                          this.numYTicks + this.y);
        context.fillText(value, 0, 0);
        context.restore();
      }
      context.restore();
    };
    //
    LineChart.prototype.drawLine = function(data, color, width){
      var context = this.context;
      context.save();
      this.transformContext();
      context.lineWidth = width;
      context.strokeStyle = color;
      context.fillStyle = color;
      context.beginPath();
      context.moveTo(data[0].x * this.scaleX, data[0].y * this.
                     scaleY);
      for (var n = 0; n < data.length; n++) {
        var point = data[n];
        // draw segment
        context.lineTo(point.x * this.scaleX, point.y * this.
                       scaleY);
        context.stroke();
        context.closePath();
        context.beginPath();
        context.arc(point.x * this.scaleX, point.y * this.scaleY,
                    this.pointRadius, 0, 2 * Math.PI, false);
        context.fill();
        context.closePath();
        // position for next segment
        context.beginPath();
        context.moveTo(point.x * this.scaleX, point.y * this.scaleY);
      }
      context.restore();
    };
    //
    LineChart.prototype.transformContext = function(){
      var context = this.context;
      // move context to center of canvas
      this.context.translate(this.x, this.y + this.height);
      // invert the y scale so that that increments
      // as you move upwards
      context.scale(1, -1);
    };
    //
    //
    window.onload = function(){
      var myLineChart = new LineChart({
        canvasId: "myCanvas",
        minX: 0,
        minY: 0,
        maxX: 200,
        maxY: 260,
        unitsPerTickX: 20,
        unitsPerTickY: 50
      });
      //
      var dps = [];
      var xVal = dps.length + 1;
      var yVal ;
      var updateInterval = 100;
      var color='blue';
      function updatedata(){
        if(xVal>200){
          myLineChart.context.clearRect(0,0,myLineChart.canvas.width,myLineChart.canvas.height);
          myLineChart.drawXAxis();
          myLineChart.drawYAxis();
          dps.length=0;
          xVal=dps.length+1;
          color=(color=='blue')?'red':'blue';
        }
        //
        yVal = xVal;
        dps.push({x: xVal,y: yVal});
        xVal++;
        myLineChart.drawLine(dps, color, 3);       
    
      };
      setInterval(function(){updatedata()}, updateInterval); 
    };
    &lt;canvas id="myCanvas" width="1200" height="600" style="border:1px solid black;"&gt;&lt;/canvas&gt;

    【讨论】:

      最近更新 更多