3

我想在画布上移动一个小部件,出于各种原因,我不想使用精灵。我正在使用最新版本的 Chrome。为了移动小部件,我“取消绘制”它,然后在另一个地方重新绘制它。'undraw',我的意思是我只是在同一个地方绘制相同的图像,但用与背景相同的颜色绘制它,所以在我绘制新的之前,小部件完全消失了。问题是当我“取消绘制”时,原始图像的痕迹仍留在画布上。我在这里探讨了相关问题,但没有找到任何有用的东西。我了解绘制单像素线并获得抗锯齿的问题,因此我将线宽设置为 2(以及其他各种非整数值),但无济于事。有人有想法么?这是一个小提琴演示,这是执行更新的函数:

function draw(){
    if(previousX !== null) {
        ctx.lineWidth = 1;
        ctx.fillStyle = '#ffffff';
        ctx.strokeStyle = '#ffffff';
        drawCircle(previousX, previousY, 20);
    }

    ctx.lineWidth = 1;
    ctx.fillStyle = '#000000';
    ctx.strokeStyle = '#000000';
    drawCircle(x, y, 20);

        console.log('drew circle (' + x + ', ' + y + ')');

    previousX = x;
    previousY = y;
}

PS我只是一个业余爱好者,在图形方面没有丰富的经验,所以如果可能的话,请稍微降低你的答案。

4

1 回答 1

3

当您使用抗锯齿绘制形状时,您正在对一些像素进行实心覆盖,但仅对边缘像素进行部分覆盖。问题是像素(暂时忽略液晶面板)是不可分割的单位。那么我们如何部分覆盖像素呢?我们使用 Alpha 通道来实现这一点。

Alpha 通道(和 Alpha 混合)将圆形边缘的颜色与其下方的颜色组合在一起。当圆圈仅部分覆盖像素时会发生这种情况。这是一个可视化此问题的快速图表。

在此处输入图像描述

颜色的混合会导致永久性的变化,通过在背景色中再次绘制圆圈并不能消除这种变化。原因:颜色混合再次发生,但这只是导致效果软化。

简而言之,重绘只会覆盖全覆盖的像素。边缘像素不完全是圆的一部分,因此您无法掩盖边缘效果。

如果您需要擦除圆圈,请考虑恢复原来的位置。您大概可以复制原始内容,然后绘制圆圈,然后当您要移动圆圈时,恢复原始内容并重复该过程。

This previous SO question可能会给您一些关于复制画布区域的想法。它使用 drawImage 方法。最好的解决方案是结合 getImageData 和 putImageData 方法。我已经修改了您的 Fiddle 示例,以向您展示如何执行此操作。您可以尝试以下代码:

var x, y, vx, vy;
var previousX = null, previousY = null;
var data = null;

function draw(){
    ctx.lineWidth = 2.5;
    ctx.fillStyle = '#000000';
    ctx.strokeStyle = '#FF0000';

    drawCircle(x, y, 20);

    previousX = x;
    previousY = y;
}

function drawCircle(x, y, r){
  // Step 3: Replace the stuff that was underneath the previous circle
  if (data != null)
  {
    ctx.putImageData(data, previousX - r-5, previousY - r-5);
  }

  // Step 1: Copy the region in which we intend to draw a circle
  data = ctx.getImageData(x - r-5, y - r-5, 2 * r + 10, 2 * r + 10);

  // Step 2: Draw the circle
  ctx.beginPath();
  ctx.arc(x, y, r, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}
于 2012-12-15T22:28:22.330 回答