HTML5 画布 - fillRect()与rect()的区别

21
在下面的代码中,如果我在两个位置使用rect()fill(),第二个fillStyle会覆盖第一个颜色指定的颜色(即,两个矩形都是绿色),但是如果我将第一个rect()更改为fillRect(),则程序按预期工作(即,第一个矩形为蓝色,第二个矩形为绿色)。为什么会这样?我以为fillRect()只是rect()再加上fill(),对吧?
ctx.translate(canvas.width/2, canvas.height/2);

ctx.fillStyle = "#5A9BDC";
ctx.fillRect(0, 0, rectWidth, rectHeight);
// ctx.rect(0, 0, rectWidth, rectHeight);
// ctx.fill();    

ctx.translate(-canvas.width/2, -canvas.height/2);

ctx.fillStyle = "#31B131";
ctx.rect(0, 0, rectWidth, rectHeight);
ctx.fill();

在 Chrome 中测试过 | Fiddle

3个回答

30

fillRect

.fillRect是一种“独立”的命令,用于绘制并填充一个矩形。

因此,如果您使用多个.fillRect命令和多个.fillStyle命令,则每个新矩形都将使用前面的填充样式进行填充。

ctx.fillStyle="red";
ctx.fillRect(10,10,10,10);  // filled with red

ctx.fillStyle="green";
ctx.fillRect(20,20,10,10);  // filled with green

ctx.fillStyle="blue";
ctx.fillRect(30,30,10,10);  // filled with blue

rect

.rect 是 Canvas 的路径命令之一。

路径命令是一组绘画命令,从 beginPath() 开始,一直持续到另一个 beginPath() 被执行。

在每个命令组中,只有最后一个样式命令会生效。

因此,如果您在路径内使用多个 .rect 命令和多个 .fillStyle 命令,则所有 .rect 的颜色都将使用最后一个 .fillStyle。

ctx.beginPath();  // path commands must begin with beginPath

ctx.fillStyle="red";
ctx.rect(10,10,10,10);  // blue

ctx.fillStyle="green";
ctx.rect(20,20,10,10);  // blue

ctx.fillStyle="blue";  // this is the last fillStyle, so it "wins"
ctx.rect(30,30,10,10);  // blue

// only 1 fillStyle is allowed per beginPath, so the last blue style fills all

ctx.fill()

1
如果您想绘制一个大矩形,则两种方法差不多。如果您想绘制许多分散的矩形,则应使用:.beginPath + 许多 .rect + .fill - markE
1
为了提供与@markE相反的观点:这个基准测试显示,直接使用fillRect每秒执行的操作数量比直接绘制甚至是带有beginPath的直接绘制要多得多。 - Christopher Byrd
1
刚试了一下,这是我得到的结果: https://jsperf.com/canvas-fillrect-vs-rect/1 显然,对于单次使用,fillRect的速度是矩形(rect)的两倍,但当涉及到数千次时,则慢了两倍。 - waterplea
这里的基准测试链接不太好。它在使用现有路径时转换坐标,而路径本身已经包含了from x / from y坐标。然后再将它们翻译回去。这当然需要时间来改变画布状态。因此,“Cached path”在该基准测试中并不具有信息量。相反,请查看我快速制作的这个链接,以比较fillRect()fill(path)。对于1000多个元素,两者表现相当良好。 - Meglio
这个测试中,我们可以看到一个fill(combined_path)调用胜过多个fill(path)和多个fillRect()调用。因此,如果您需要使用相同的样式绘制多个多边形,则最高效的方法似乎是创建一个组合路径,然后进行一次填充。 - Meglio
显示剩余3条评论

6
据我所知,canvas 有三个“矩形”函数:fillRectstrokeRectrect
ctx.rect(0,0,rectWidth,rectHeight); // create some shape, there is nothing on the canvas yet
ctx.stroke(); // draw stroke of the shape
ctx.fill();   // fill the shape

有两个快捷键:

ctx.strokeRect(0,0,rectWidth,rectHeight); // shortcut to stroke rectangle
ctx.fillRect(0, 0, rectWidth, rectHeight); // shortcut to fill rectangle

因此,您的fill调用可以仅填充使用rect创建的形状。

我知道所有这些方法以及fillRect应该做什么,但它与rectfill的工作方式略有不同(至少对我来说是这样)。PS:fill将填充任何形状,甚至是通过绘制线条创建的形状。 - Sourabh
将 fiddle 中的 ctx.fillRect(0, 0, rectWidth, rectHeight); 行注释掉,并取消下面两行的注释,观察发生了什么。我的问题是为什么会这样。 - Sourabh

0
如果您想为不同的路径命令使用不同的颜色,可以在每个命令之前调用beginPath()
ctx.beginPath();  
ctx.fillStyle="red";
ctx.rect(10,10,10,10);
ctx.fill()

ctx.beginPath()
ctx.fillStyle="green";
ctx.rect(20,20,10,10);  
ctx.fill()

ctx.beginPath()
ctx.fillStyle="blue";  
ctx.rect(30,30,10,10);  
ctx.fill()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接