HTML 5画布剪辑非常昂贵

Stn*_*ire 8 javascript performance html5 canvas clip

我使用带有chrome的canvas clip()会遇到严重的性能问题.

我做了一个测试案例来说明.

即使在这样的简单情况下,红色矩形也会闪烁,就好像需要花费太多时间来重绘一样,并且CPU分析显示clip()方法占用了大约10%的CPU.

在我的真实程序中,它达到16%并继续增加每一帧,直到画布几乎冻结浏览器..

我使用剪辑时有什么问题吗?

谢谢你的任何建议,

问候.

小智 13

原因

与/ 不同,插入beginPath()as rect()添加到路径.这里发生的是矩形正在累积,最终会减慢削减速度.fillRect()strokeRect()

这与setInterval无法与监视器/屏幕刷新同步的使用相结合,使问题恶化.

详细说明后者:

使用setInterval()/ setTimeout()可能导致撕裂,当绘图处于其操作的"中间"未完全完成并且发生屏幕刷新时发生.

setInterval只能取整数值,你需要16.67 ms来逐帧同步(@ 60Hz).即使setInterval 可以采用浮点数也不会使计时器与监视器计时同步,因为计时器机制根本不受监视.

要解决这个问题,请始终使用requestAnimationFrame图纸与屏幕更新同步.这与监视器刷新直接相关,并且是一种比另一种更低级别和更高效的实现,并且是为此目的而制作的,因此得名.

解决方案嵌入上面的两个修复程序

请参见修改后的bin.

未来访客的代码:

function draw() {

  context.fillStyle = '#000';
  context.fillRect(0, 0, width, height);

  context.save();

  context.beginPath();            /// add a beginPath here
  context.rect(0, 0, 100, 100);
  context.clip();

  context.fillStyle = '#ff0000';
  context.fillRect(0, 0, 200, 200);

  context.restore();

  requestAnimationFrame(draw);    /// use rAF here
}

canvas.width = width;
canvas.height = height;
canvas.style.width = width+'px';
canvas.style.height = height+'px';

requestAnimationFrame(draw);      /// start loop
Run Code Online (Sandbox Code Playgroud)

PS:如果你需要停止循环注入条件以在循环内运行rAF,即:

if (isPlaying) requestAnimationFrame(draw);
Run Code Online (Sandbox Code Playgroud)

BTW没有必要,closePath()因为这将通过规范为您隐含.您可以添加,如果你想,但调用clip()(或fill()等)将做到这一点你(规格是解决浏览器的实施者):

在计算剪切区域时,必须隐式关闭打开的子路径

  • 非常感谢!我没有考虑过 beginPath(),你的解释非常有道理,并解释了为什么随着时间的推移它变得越来越慢。requestAnimationFrame 参数也非常有用,谢谢,问题解决了!:) (2认同)
  • 非常感谢。我被这个问题困了 2 天了。我没有发现剪辑是问题所在。我的应用程序每一帧都变得越来越慢,直到我偶然发现这个问题,我才知道是什么导致了问题。 (2认同)