我将画布分成两部分。我需要在每一边画画,为两者定义剪裁区域。每一方都必须做类似的事情,比如用颜色绘制文字,绘制圆圈等。
我已经读过你应该将fillStyle和strokeStyle的变化保持在最低限度。但是我也读过你必须保存和恢复到最低限度。
那么什么更快?
保存画布,剪切左侧,为多种颜色执行该侧的所有绘图,然后恢复并重复右侧?
或者......设置第一个文字颜色。剪辑左侧。绘制此颜色的所有文本。然后剪辑右侧(不重新填充fillStyle)并为右侧绘制所有相同的颜色文本。然后设置下一个fillStyle,然后剪切每一面并为这种颜色绘制文字?等
有人知道吗?
此外,如果我设置一个剪辑区域,然后设置另一个剪辑区域而不保存和恢复,实际发生了什么?
答案 0 :(得分:1)
与往常一样,您必须使用自己的项目代码进行性能测试。
上下文维护与其当前状态相关的内部变量(颜色,变换,当前路径,应用合成等)。
您可以使用context.save保存当前上下文状态的副本。然后在更改上下文状态后,您可以使用context.restore恢复原始上下文状态。注意:如果需要,您可以嵌套多个保存/恢复。
fillStyle是一个上下文状态,因此更改fillStyle ='green'后跟fillStyle ='blue'比保存/恢复更快,因为只有1个状态变量被重置,而不是在保存/恢复期间完成的每个状态变量。 / p>
关键是你经常通过保存+重置单个状态值而不是完整的context.save/context.restore来获得性能。
最小化状态更改将最大限度地提高性能,因此,例如,批处理所有绿色图形将有助于提高性能。
剪辑是一项复杂的操作,比简单的状态更改(如更改fillStyle)更昂贵。通过GPU加速,剪辑可以更有效地完成,因此比没有GPU的剪辑要便宜得多。
关于更改剪辑区域:剪辑始终仅在最后一个定义的路径上完成。因此,设置另一个剪切区域将撤消先前的剪切区域(除非前一个和当前路径相同)。
关于左右剪裁区域:如果您的设计允许,您可能希望将左侧和右侧剪裁区域的两者定义为1个组合剪裁区域。由于可以断开路径,因此允许使用2个非交叉部分定义1个剪切路径。
汽车公司警告:“你的里程可能会有所不同”。但你可能会对这种方法进行测试:
在1个剪切路径中定义左右剪裁区域
设置fillStyle =“red”并一次性完成所有红色绘图(左右)
重置fillStyle =“blue”并立即执行所有蓝色图纸等。
最后一个想法:所有项目都有自己独特的要求,因此您必须对您的实际代码进行性能测试,而不是完全依赖于一般规则。不要跳过性能测试 - 特别是如果你要在画布上进行部署,画布本质上很慢。
祝你的项目好运!
[关于裁剪的补充说明]
裁剪区域是半永久性的。一旦设置,即使再次发出context.clip命令,它仍然保持不变。新的剪辑命令将进一步限制所有先前的剪辑区域。
要清除剪切路径,您必须将剪辑包装在context.save&amp ;; context.restore()。或者,调整画布大小将强制将上下文状态恢复为默认值 - 但调整大小也将清除所有画布内容:canvas.width=canvas.width
以下是由左右方块组成的单一路径的示例:
// left square
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(150,50);
ctx.lineTo(150,150);
ctx.lineTo(50,150);
ctx.closePath();
// right square
ctx.moveTo(200,50);
ctx.lineTo(300,50);
ctx.lineTo(300,150);
ctx.lineTo(200,150);
ctx.closePath();
ctx.strokeStyle="red";
ctx.stroke();
从左+右路径创建剪裁区域。
// create a clipping region from the left+right path
ctx.clip();
用绿色填充整个画布。绿色只会在裁剪区域内(左右方格内)绘制。
// draw a green rect over the entire canvas
// the green will only be drawn inside the clipping region
ctx.fillStyle="green";
ctx.fillRect(0,0,canvas.width,canvas.height);
如果添加第二个剪切区域,结果是绘图仅在所有剪切路径的并集中可见。
因此,如果第二个剪切区域与第一个剪切区域略微重叠,则所有图形仅在第一个和第二个剪切区域的并集内可见。下图中的蓝色部分是2个剪切路径的并集。
ctx.beginPath();
ctx.moveTo(0,115);
ctx.lineTo(canvas.width,115);
ctx.lineTo(canvas.width,135);
ctx.lineTo(0,135);
ctx.clip();
ctx.closePath();
ctx.fillStyle="blue";
ctx.fillRect(0,0,canvas.width,canvas.height);
答案 1 :(得分:1)
一些想法:
要处理两个屏幕,您可以并排使用两个画布。
即使您只保留一个画布,也可以通过以下方式减少裁剪的使用:
- 擦除屏幕的左半部分
- 画左侧部分
- 擦除右侧部分
- 夹在右半部分
- 画右边部分
因此,您只剪辑一次。
对于你的颜色与剪辑问题,剪裁比改变颜色要贵很多 如果一个人继续剪辑而没有保存/恢复,剪辑区域将加起来。
对于你的strokeStyle / fillStyle,是的,这是一个成本,特别是如果使用颜色名称('蓝色'),或rgb' rgb()'字符串或更糟糕' hsl()'字符串。
所以这是一个技巧:尽可能预先计算并存储颜色。只需使用上下文转换!
var blue = 'hsl(23, 75%, 75%)';
context.fillStyle = blue ;
blue = context.fillStyle ;