Canvas 重新绘制卡住(性能问题)
Canvas re-drawing gets stucked (performance-problem)
我要为我的 Raspi 项目创建一个 GUI。 Raspi3 上有 Nodejs 运行,它运行一个 NodeJs-Server,然后在 kiosk 模式下用 Chromium 请求它。
此 GUI 的一页需要可视化 48 个电位器、12 个按钮、8 个推子的状态。 NodeJs-Server 通过 websocket 向客户端发送数据(被用户修改),客户端重绘整个 canvas。到目前为止,一些元素工作正常:
works fine but with a slight delay if you look closer
现在问题是,随着需要绘制的元素数量的增加,性能下降到无法接受的延迟时间。
works, but with a way too big dalay, as more elements are drawn
这些甚至还不到需要绘制的一半。
我现在很困惑,因为在我决定走那条路之前,我读到了 canvas 有多快,如果我停用所有 canvas-绘图并简单地 console.log()
通过 websocket 传入的数据,它像实时一样快。
所以我做错了什么?也许最好不要在每次值更改时绘制整个 canvas,而是为 canvas 设置动画?也许有人对此有经验?
Here is the code.. 当您查看 assets/js/menu.class.js
时,这是生成 canvas 的文件。每次值更改时,函数 createControllerGUI(options)
都会通过 websocket 调用。
Canvas 很快,但仍然 cpu 密集。速度也随着平台的变化而变化。
您的函数执行每次更改的所有绘图操作。这些操作有描边、填充、居中对齐的文本等等(我没有仔细看)。
有一些方法可以优化绘图操作。
部分重绘
也许是最有效的。
跟踪小部件的位置,跟踪消息之间更改的数据并仅绘制差异。
在小部件占用的区域上使用 clearRect 并重绘它。不要触摸其他像素。
除非章鱼正在使用硬件,否则每帧最多会更改 2 或 3 个小部件。
一下子划完。
您可以一次跟踪所有需要的路径,而不是在每个小部件的基础上进行描边,在更改小部件时使用 moveTo 到新位置,并在循环结束时使用单个描边操作。
缓存
例如,如果您有一些旋转控件,您可以在一个小的单独 canvas 上绘制一次它们,然后使用该 canvas 作为源图像以不同的角度绘制,如果您需要表示一个旋转的控件。
DrawImage 通常使用硬件操作进行优化,而单个填充和描边可能不会。
可能还有其他方法,您可以查看可以为您执行此操作的高级库,公开小部件逻辑而不是低级绘图操作。
我要为我的 Raspi 项目创建一个 GUI。 Raspi3 上有 Nodejs 运行,它运行一个 NodeJs-Server,然后在 kiosk 模式下用 Chromium 请求它。
此 GUI 的一页需要可视化 48 个电位器、12 个按钮、8 个推子的状态。 NodeJs-Server 通过 websocket 向客户端发送数据(被用户修改),客户端重绘整个 canvas。到目前为止,一些元素工作正常:
works fine but with a slight delay if you look closer
现在问题是,随着需要绘制的元素数量的增加,性能下降到无法接受的延迟时间。
works, but with a way too big dalay, as more elements are drawn
这些甚至还不到需要绘制的一半。
我现在很困惑,因为在我决定走那条路之前,我读到了 canvas 有多快,如果我停用所有 canvas-绘图并简单地 console.log()
通过 websocket 传入的数据,它像实时一样快。
所以我做错了什么?也许最好不要在每次值更改时绘制整个 canvas,而是为 canvas 设置动画?也许有人对此有经验?
Here is the code.. 当您查看 assets/js/menu.class.js
时,这是生成 canvas 的文件。每次值更改时,函数 createControllerGUI(options)
都会通过 websocket 调用。
Canvas 很快,但仍然 cpu 密集。速度也随着平台的变化而变化。
您的函数执行每次更改的所有绘图操作。这些操作有描边、填充、居中对齐的文本等等(我没有仔细看)。
有一些方法可以优化绘图操作。
部分重绘
也许是最有效的。 跟踪小部件的位置,跟踪消息之间更改的数据并仅绘制差异。 在小部件占用的区域上使用 clearRect 并重绘它。不要触摸其他像素。 除非章鱼正在使用硬件,否则每帧最多会更改 2 或 3 个小部件。
一下子划完。
您可以一次跟踪所有需要的路径,而不是在每个小部件的基础上进行描边,在更改小部件时使用 moveTo 到新位置,并在循环结束时使用单个描边操作。
缓存
例如,如果您有一些旋转控件,您可以在一个小的单独 canvas 上绘制一次它们,然后使用该 canvas 作为源图像以不同的角度绘制,如果您需要表示一个旋转的控件。 DrawImage 通常使用硬件操作进行优化,而单个填充和描边可能不会。
可能还有其他方法,您可以查看可以为您执行此操作的高级库,公开小部件逻辑而不是低级绘图操作。