如何删除 canvas 元素两侧的细边框?

How to remove thin border on 2 sides of canvas element?

更新: Link to JSFiddle with workable code

我正在制作一个网站并创建了两个 canvas 元素的堆栈:顶部 canvas 上下文是一个白色矩形,它“擦除”以显示加载到底部的图像 canvas上下文。该功能正常工作。我的问题是,当我包含 setInterval 代码行时,canvas 堆栈 的右侧和底部会出现灰色细边框。

当我删除这个计时器变量(见下面的代码)时它会消失,但如果我向 canvas 元素添加任何类型的状态检查(如 onmouseout),它会重新出现。这是屏幕截图:

知道为什么会这样吗?类似的SOquestions/solutions没有解决我的问题

window.onload = function() {
    var speaker = document.getElementById('speaker');
    //speaker.onload = MoveElement(speaker, "right", 1000);

    //Create canvases & contexts
    var canvas = document.getElementById('canvas');
    var ctxB = canvas.getContext('2d');
    var canvas2 = document.getElementById('canvas2');
    var ctxT = canvas2.getContext('2d');

    //Get waterfall image object
    var waterfall = document.getElementById('waterfall');

    //Set canvas w&h properties
    canvas.width = canvas2.width = .3*waterfall.width;
    canvas.height = canvas2.height = .3*waterfall.height;

    //Populate Bottom canvas with waterfall image
    ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);

    //Populate Top canvas with white rectangle
    ctxT.fillStyle = "white";
    ctxT.fillRect(0, 0, canvas2.width, canvas2.height);

    //Make Top canvas "erasable"
    canvas2.addEventListener('mousemove', event => {
        var x = event.offsetX;
        var y = event.offsetY;  
        const eraseSize = 15;
        ctxT.clearRect(x-eraseSize/2, y-eraseSize/2, eraseSize, eraseSize);
    });
}

//Set interval timer to repeatedly execute TransparencyCheck()
var timer = setInterval(TransparencyCheck, 500);

//Check that all pixel alpha values = 0
function TransparencyCheck() {
    var canvas2 = document.getElementById('canvas2');
    var ctxT = canvas2.getContext('2d');
    var imageDataTop = ctxT.getImageData(0, 0, canvas2.width, canvas2.height);
    var counter = 0;

    for (var i = 3; i < imageDataTop.data.length; i += 4) {
        if (imageDataTop.data[i] == 0) {
            counter++;
        }
    if (counter == imageDataTop.data.length/4) {
        canvas2.style.opacity = "0";
        }
    }
}
#stack {
    position: relative;
}
#stack canvas {
    position: absolute;
    display: block;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 150px;
}
            <img hidden src="https://sample-videos.com/img/Sample-jpg-image-50kb.jpg" alt="issue here" id="waterfall" />
      
        <div id="stack">
            <canvas id="canvas"></canvas>
            <canvas id="canvas2" onmouseout="TransparencyCheck()"></canvas>
        </div>
 

问题是 canvas 的尺寸被计算为基础图像尺寸的分数 (0.3)。这可能会导致 'part pixel' 问题。也就是说,系统必须决定如何显示 CSS 像素的一小部分,而在现代屏幕上,几个屏幕像素用于显示一个 CSS 像素。一个screen pixwl在这个过程中可以得到'left behind'(即还在显示)

绕过这个问题的一个稍微老套的方法(但我不知道其他方法)是将底部 canvas 的大小减小几个像素,这样我们就可以绝对确定任何剩余的都在开始时顶部的白色 canvas。

此代码段通过将宽度和高度减去 2 像素来加倍确定。

顺便说一句,我从问题指向的代码笔中复制了代码,它作为一个 SO 代码段工作正常。这是:

window.onload = function() {
  var speaker = document.getElementById('speaker');
  //speaker.onload = MoveElement(speaker, "right", 1000);

  //Create canvases & contexts
  var canvas = document.getElementById('canvas');
  var ctxB = canvas.getContext('2d');
  var canvas2 = document.getElementById('canvas2');
  var ctxT = canvas2.getContext('2d');

  //Get waterfall image object
  var waterfall = document.getElementById('waterfall');

  //Set canvas w&h properties
  canvas.width = canvas2.width = .3 * waterfall.width;
  canvas.width = canvas.width - 2;
  canvas.height = canvas2.height = .3 * waterfall.height;
  canvas.height = canvas.height - 2;


  //Populate Bottom canvas with waterfall image
  ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);

  //Populate Top canvas with white rectangle
  ctxT.fillStyle = "white";
  ctxT.fillRect(0, 0, canvas2.width, canvas2.height);

  //Make Top canvas "erasable"
  canvas2.addEventListener('mousemove', event => {
    var x = event.offsetX;
    var y = event.offsetY;
    const eraseSize = 15;
    ctxT.clearRect(x - eraseSize / 2, y - eraseSize / 2, eraseSize, eraseSize);
  });
}

//Set interval timer to repeatedly execute TransparencyCheck()
var timer = setInterval(TransparencyCheck, 5000);

//Check that all pixel alpha values = 0
function TransparencyCheck() {
  var canvas2 = document.getElementById('canvas2');
  var ctxT = canvas2.getContext('2d');
  var imageDataTop = ctxT.getImageData(0, 0, canvas2.width, canvas2.height);
  var counter = 0;

  for (var i = 3; i < imageDataTop.data.length; i += 4) {
    if (imageDataTop.data[i] == 0) {
      counter++;
    }
    if (counter >= imageDataTop.data.length / 4) {
      canvas2.style.opacity = "0";
      clearTimeout(timer);
      alert('all top canvas erased');
    }
  }
}
#stack {
  position: relative;
}

#stack canvas {
  position: absolute;
  display: block;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 150px;
}
<img hidden src="https://sample-videos.com/img/Sample-jpg-image-50kb.jpg" alt="issue here" id="waterfall" />

<div id="stack">
  <canvas id="canvas"></canvas>
  <canvas id="canvas2" onmouseout="TransparencyCheck()"></canvas>
</div>