JavaScript canvas clearRect在使用浮点坐标时会留下边框

时间:2014-02-20 09:35:09

标签: javascript html5 canvas

我在HTML5画布上使用clearRect来重绘矩形。使用浮点坐标时,clearRect会在画布上留下我的矩形边框。

以下代码演示了使用整数坐标完全清除矩形的问题,而使用浮点的矩形留下边框。

<html>
<head>
</head>
<body>
<script type="text/javascript" >

var canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
canvas.style.border = "1px solid";
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
ctx.fillRect(20.1,20.1,30,30);
ctx.clearRect(20.1,20.1,30,30);

ctx.fillRect(50,50,30,30);
ctx.clearRect(50,50,30,30);

</script>
</body>
</html>

生成的画布如下所示: clearRect example

我可以通过清除更大的区域来解决这个问题,但这会增加清除风险并重新绘制相邻形状的风险。例如,这是建议的:I can't completely clear the transformed rectangle in <canvas>

我可以使用整数坐标来修复它,但这不是此应用程序中的一个选项。

是否有其他方法可以使clearRect实际清除所有绘制的矩形而不清除更大的区域或使用整数坐标?

2 个答案:

答案 0 :(得分:4)

画布中的所有点实际上都以中间坐标(0.5,0.5)为中心 如果你想绘制一个像素厚的黑线,你必须用中心坐标绘制它 如果你在一个整数边界上绘制它,你实际上绘制了两条像素粗线,两条线的不透明度都较低,导致以深灰色而不是黑色绘制的粗线:

这是一张显示此图片的图片,缩放了3次:

enter image description here

更一般地说,0.5边界以外的任何坐标都将绘制成与其到中点的距离成比例的不透明度 这是一组从整数边界开始的水平线段,然后每20个像素移动一个像素的1/10:

enter image description here

缩放4次:
enter image description here

我们可以看到,只有居中时我们才真正拥有1像素线。

对于您的问题,您无法部分地&#39;清除一个像素:像素是这里的终极单位,因此,由于颜色已经混合,您只能清除整个像素,或者只是减弱其强度(这是您看到的结果)。

我可以想到两个解决方案:

  • 而不是清除,重新绘制除了您不想要的内容之外的所有内容。为此,您必须处理某种场景图,这意味着:您需要拥有需要绘制的所有对象的集合(例如,在数组中保存),并且在绘制时,您擦除所有内容,重绘除矩形之外的所有内容。

  • 在场景后面处理一个更大的画布,它将具有比用户画布更高的分辨率。这是你绘制的,具有更好的质量,并在绘制后将其复制到低分辨率用户画布。 绘制具有整数大小的0.5边界(例如,矩形的宽度/高度)。这个主画布可能会大4或8倍。画布的最大尺寸是有限的,因此如果您定位所有浏览器,请注意这一点,它们并不都允许相同的最大尺寸(低于6400X6400应该没问题,但不确定)。您可以处理多个后台画布以超出该限制,并进行一些额外的工作。

(解决方案2的Rq:确保在复制前禁用图像平滑以避免伪影)。

((图纸的小提琴在这里:jsbin.com/xucuxoxo/1/))

编辑:在创建上下文后立即从(0.5; 0.5)翻译上下文是一个好习惯。然后,您将始终绘制整数坐标。这样,您可以确保所有(例如)1像素粗线实际上绘制一个像素厚。用地板或天花板测试圆角,然后选择你喜欢的那个。

答案 1 :(得分:3)

Html画布总是使用抗锯齿来“治愈锯齿”。

消除锯齿通过在线条上添加半透明像素来直观地平滑线条,因此眼睛会被愚弄,看到线条不那么锯齿。

绘制矩形时,这些半透明像素会自动应用到矩形的30,30区域之外。

这意味着您的30x30矩形实际上略大于30x30。

执行context.clearRect时,浏览器无法清除这些额外的半透明像素。

这就是为什么未清除像素显得“幽灵般” - 它们是半透明的。

不幸的是,目前无法关闭html canvas原始绘图(行等)的抗锯齿。

您发现了2个最快的解决方案:

  • 圆形像素绘制坐标为整数
  • 清除比原始图纸略大的区域

您可以使用getImageData / putImageData手动绘制像素,而无需消除锯齿。这种手动方法有效,但性能成本很高。性能下降使得仅清除绘制区域的目的无效。

底线:您已经发现了canvas目前提供的最佳解决方案: - (