使用浮点坐标时,JavaScript canvas clearRect会保留边框 [英] JavaScript canvas clearRect leaves borders when using floating point coordinates

查看:295
本文介绍了使用浮点坐标时,JavaScript canvas clearRect会保留边框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using clearRect on a HTML5 canvas to redraw a rectangle. When using floating point coordinates the clearRect leaves a border from my rectangle on the canvas.

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

The following code demonstrates the problem with the rectangle using integer coordinates being fully cleared while the one using floating point leaves a border.

<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>

生成的画布如下所示:

The resulting canvas looks like this:

我可以通过清除更大的区域来解决这个问题,但这会增加清算风险并且必须重新绘制相邻的形状。例如,这里建议:我无法完全清除转换矩形在< canvas>

I can fix this by clearing a larger region, but that increases the risk of clearing and having to redraw adjacent shapes. This is for example suggested here: I can't completely clear the transformed rectangle in <canvas>

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

I can fix it by using integer coordinates, but that is not an option in this application.

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

Are there other ways to make clearRect actually clear all of the drawn rectangle without clearing a larger region or using integer coordinates?

推荐答案

画布中的所有点实际上都是以它们的中间坐标(0.5,0.5)为中心。

如果你想绘制一个像素厚的黑线,你将拥有用中心坐标绘制它。

如果你在整数边界上绘制它,你实际上会画出两条像素粗线,两条线的不透明度都较低,导致画一条较粗的线以深灰色而不是黑色:

All points in canvas are in fact centered in their middle coordinates (0.5, 0.5).
If you want to draw a black line one pixel thick, you'll have to draw it with centered coordinates.
If you draw it on an integer boundary, you'll in fact draw a two pixel thick lines both with lower opacity, leading to a thicker line drawn in dark gray instead of black :

这是一张显示此图片的图片,放大了3倍:

Here's a picture showing this, zoomed 3 times :

更一般地说,0.5边界以外的任何坐标都将使用与其到中点的距离成比例的不透明度绘制。

这是一组从整数边界开始的水平线段,然后移动1/10每20像素一个像素:

More generally, any coordinates off the 0.5 boundary will be drawn with an opacity proportional to its distance to mid point.
Here's a set of horizontal line segments starting on an integer boundary, then shifted 1/10th of a pixel every 20 pixels :

放大了4倍:

zoomed 4 times :

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

We can see that we really have a 1 pixel line only when centered.

对于你的问题,你无法部分清除一个像素:像素是这里的终极单位,所以由于颜色已经混合,你只能清除整个像素,或只是减弱其强度(这是你看到的结果)。

For your issue, there's no way you 'partially' clear a pixel : pixel is the ultimate unit here, so since colors have already been mixed, you can only either clear whole pixel, or just attenuate its intensity (which is the result you see).

我能想到两个解决方案:

I can think of two solutions :


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

  • rather than clearing, redraw everything except what you don't want any more. For this you have to handle some kind of scene graph, meaning : you need to have a collection of all the objects that needs drawing (held within an array for instance), and at draw time, you erase everything, redraw everything except the rectangle.

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

handle a bigger canvas behind the scene, that will have a higher resolution than the user canvas. This is were you draw, with better quality, and after drawing you copy it to the low-resolution user canvas. Draw on 0.5 boundaries with integer sizes (width/height of your rect for instance). This main canvas might be 4 or 8 times bigger. The maximum size of the canvas is limited, so watch out for this if you target all browsers, they do not all allow the same max size (below 6400X6400 should be fine, but not sure about it). You can handle multiples backstage canvas to go beyond that limit, with a little bit of extra work.

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

(Rq for solution 2 : be sure to disable image smoothing before copying to avoid artifacts).

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

(( the fiddle for the drawings is here : jsbin.com/xucuxoxo/1/ ))

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

Edit : it is a good practice to translate the context from (0.5;0.5) right after you created it. Then you will always draw integer coordinates. This way, you ensure that all, say, 1 pixel thick line will actually be drawn one pixel thick. Test rounding with floor or ceil, and choose the one you prefer.

这篇关于使用浮点坐标时,JavaScript canvas clearRect会保留边框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆