Erasing previously drawn lines on an HTML5 canvas

后端 未结 5 1585
臣服心动
臣服心动 2020-12-03 07:36

To play around with HTML5 canvas, I decided to make an app which draws an analogue clockface. Everything\'s fine, except that old lines don\'t get erased in the way that I w

相关标签:
5条回答
  • 2020-12-03 07:57

    Instead of erasing the things you don't want you can:

    1. save the state of the canvas
    2. draw the things you don't want
    3. restore the canvas to the saved state to 'erase' them

    This can be accomplished pretty easily using ImageData:

    var canvas = document.querySelector('canvas'),
        context = canvas.getContext('2d');
    
    context.fillStyle = 'blue';
    context.fillRect(0,0,200,200);
    
    // save the state of  the canvas here
    var imageData = context.getImageData(0,0,canvas.width,canvas.height);
    
    // draw a red rectangle that we'll get rid of in a second
    context.fillStyle = 'red';
    context.fillRect(50,50,100,100);
    
    setTimeout(function () {
        // return the canvas to the state right after we drew the blue rect
        context.putImageData(imageData, 0, 0);
    }, 1000);
    <canvas width=200 height=200>

    0 讨论(0)
  • 2020-12-03 08:00

    For reasons that I could expand upon, you should consider clearing your canvas and redrawing it entirely unless there are performance or compositing reasons not to.

    You want clearRect, something like this:

    //clear the canvas so we can draw a fresh clock
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    
    //redraw your clock here
    /* ... */
    
    0 讨论(0)
  • 2020-12-03 08:00

    The reason you can't just redraw the line in white and hope for it to erase the old line is because there might be some anti-aliasing/bleeding. You'll also notice that a straight horizontal line drawn on a pixel versus a half-pixel looks very different because of this.

    When you do your white "erase" lines, try drawing them with a larger lineWidth by about 3 or 4. That should work for your case.

    You should also draw all of the white lines first, then all of the black lines, in case they intersect.

    0 讨论(0)
  • 2020-12-03 08:02

    A quick and easy way to clear a canvas is to set the width:

    context.canvas.width = context.canvas.width;
    
    0 讨论(0)
  • 2020-12-03 08:03

    My solution is double buffering :

    var shapes = 
      [{type:"circle", x:50, y:50, radious:40, lineWidth:2, strokeStyle:"#FF0000", fillStyle:"#800000"}
      ,{type:"rectangle", x:50, y:50, width:100, height: 100, lineWidth:2, strokeStyle:"#00FF00", fillStyle:"#008000"}
      ,{type:"line", x1:75, y1:100, x2:170, y2:75, lineWidth:3, strokeStyle:"#0000FF"}
      ];
    
    step1();
    setTimeout(function () {
      step2();
      setTimeout(function () {
        step3();
      }, 1000);
    }, 1000);
    
    function step1() {
      clearCanvas('myCanvas1');
      shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
    };
    
    function step2() {
      clearCanvas('myCanvas2');
      shapes.pop();
      shapes.forEach((sh) => { drawShape('myCanvas2', sh); });
      showOtherCanvas('myCanvas2', 'myCanvas1');
    };
    
    function step3() {
      clearCanvas('myCanvas1');
      shapes.pop();
      shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
      showOtherCanvas('myCanvas1', 'myCanvas2');
    };
    
    function showOtherCanvas(cnv1, cnv2) {
      var c1 = document.getElementById(cnv1);
      var c2 = document.getElementById(cnv2);
      
      c1.style['z-index'] = 3;
      c2.style['z-index'] = 1;
      c1.style['z-index'] = 2;
    }
    
    function clearCanvas(canvasID) {
      var canvas = document.getElementById(canvasID);
      var ctx = canvas.getContext('2d');
      
      ctx.fillStyle="#FFFFFF";
      ctx.fillRect(0,0,480,320);
    } 
    
    function drawShape (canvasID, info) {
      switch (info.type) {
        case "line"      : drawLine(canvasID, info);
        case "rectangle" : drawRectangle(canvasID, info);
        case "circle"    : drawCircle(canvasID, info);
      }
    }
    
    function drawLine (canvasID, info) {
      var canvas = document.getElementById(canvasID);
      var ctx = canvas.getContext('2d');
      
      ctx.strokeStyle = info.strokeStyle;
      ctx.lineWidth = info.lineWidth
    
      ctx.beginPath();
      ctx.moveTo(info.x1, info.y1);
      ctx.lineTo(info.x2, info.y2);
      ctx.stroke();
    }
    
    function drawRectangle (canvasID, info) {
      var canvas = document.getElementById(canvasID);
      var ctx = canvas.getContext('2d');
      
      ctx.fillStyle = info.fillStyle;
      ctx.strokeStyle = info.strokeStyle;
      ctx.lineWidth = info.lineWidth
    
      ctx.fillRect(info.x, info.y, info.width, info.height);
      ctx.strokeRect(info.x, info.y, info.width, info.height);
    }
    
    function drawCircle (canvasID, info) {
      var canvas = document.getElementById(canvasID);
      var ctx = canvas.getContext('2d');
      
      ctx.fillStyle = info.fillStyle;
      ctx.strokeStyle = info.strokeStyle;
      ctx.lineWidth = info.lineWidth
    
      ctx.beginPath();
      ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
      ctx.fill();
    
      ctx.beginPath();
      ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
      ctx.stroke();
    }
    <canvas id="myCanvas2" width="480" height="320"
    	style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:1">
    </canvas>
    <canvas id="myCanvas1" width="480" height="320"
    	style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:2">
    </canvas>

    The change is so fast you won't see any flicker.

    0 讨论(0)
提交回复
热议问题