绘制多路径时 react-native-canvas 的性能优化
Performance optimization for react-native-canvas when drawing many paths
我想在我的 React Native 应用程序中镜像模拟段显示。段显示相当复杂,它由 100 多个不同的段组成。它包含三个 7 段数字显示和一个包含 20 个元素的进度条。其余的是自定义形状和符号,提供有关其所连接机器的当前状态的信息。我对 HTML canvas 有一些经验,并找到了 React Native 模块 react-native-canvas 并想尝试一下。但是,与我可以在网络浏览器中使用的 HTML canvas 相比,使用 react-native-canvas 似乎相当慢。
这是我的做法:
- 我在我的组件中导入模块:
import Canvas, {Image as CanvasImage, Path2D, ImageData} from 'react-native-canvas';
- 向我的渲染函数添加一个 canvas 元素:
<Canvas ref={this.handleCanvas}/>
- 存储对 canvas 的引用并设置其大小:
handleCanvas = (canvas) => {
if (this.myCanvas === null && canvas !== null){
canvas.width = 250;
canvas.height = 250;
this.myCanvas = canvas;
}
}
- 然后我可以为每个段调用一个 "draw" 绘制二维路径的函数:
draw(ctx){
ctx.save();
ctx.strokeStyle="#000000";
ctx.lineWidth=2;
ctx.lineJoin="round";
ctx.font=" 10px sans-serif";
ctx.beginPath();
ctx.moveTo(158.108112514019,24.324327290058136);
ctx.lineTo(159.45946389436722,24.324327290058136);
ctx.lineTo(160.13513958454132,25.67567867040634);
...
ctx.lineTo(162.16216665506363,25.00000298023224);
ctx.fill("nonzero");
ctx.stroke();
ctx.restore();
}
我得到这样的上下文:
var ctx = this.myCanvas.getContext('2d');
我制作了一个有 13 个片段的原型。每个线段有大约 50 个节点,我一次绘制了所有 13 个线段。在我的 React Native 应用程序中,这需要将近一秒钟的时间来绘制,这太慢了(还有 90 多个片段我还没有渲染......)。如果我在 HTML canvas 和 Google Chrome 上绘制相同的路径,只需要 2-5 毫秒。
有没有人知道如何提高性能?或者是否有另一个库更适合我的目的?`
提前致谢!
感谢您发布如此详细的问题。 React Native Canvas 与 HTML canvas 相比相当慢,因为每个指令都被传送到 WebView。我能想到的一种提高性能的潜在方法是使用 Path2D 因为对象在呈现之前包含多个指令。你能试试看它是否提高了性能吗?
Iddans 的回答是正确的,因为我无法 post 作为对他的回答的评论来详细说明我们是如何解决这个问题的,我正在 post 自己一个新的答案。
正如 Iddan 所说,正确的解决方案确实是尽量减少发送到 canvas 的指令数量。
我们更改了问题的第 4 点。我们没有直接使用 ctx.lineTo(...)
语句绘制路径,而是将所有 SVG 路径提取为字符串并将它们存储在数组中:
const svgPaths = [
'M713.33,497.34a38.67 ... ',
...
]
对于每个渲染周期,我们决定要渲染所有 SVG 路径的哪个子集并将它们存储在一个新数组中,然后我们创建所有所需 svg 路径的单个 Path2D 对象
const svgPathsSubset = [svgPaths[1], svgPaths[7], ... ]
const pathToRender = new Path2D(this.myCanvas, svgPathsSubset)
const ctx = this.myCanvas.getContext('2d')
ctx.fill(pathToRender)
这非常快,只需几毫秒。
我想在我的 React Native 应用程序中镜像模拟段显示。段显示相当复杂,它由 100 多个不同的段组成。它包含三个 7 段数字显示和一个包含 20 个元素的进度条。其余的是自定义形状和符号,提供有关其所连接机器的当前状态的信息。我对 HTML canvas 有一些经验,并找到了 React Native 模块 react-native-canvas 并想尝试一下。但是,与我可以在网络浏览器中使用的 HTML canvas 相比,使用 react-native-canvas 似乎相当慢。
这是我的做法:
- 我在我的组件中导入模块:
import Canvas, {Image as CanvasImage, Path2D, ImageData} from 'react-native-canvas';
- 向我的渲染函数添加一个 canvas 元素:
<Canvas ref={this.handleCanvas}/>
- 存储对 canvas 的引用并设置其大小:
handleCanvas = (canvas) => {
if (this.myCanvas === null && canvas !== null){
canvas.width = 250;
canvas.height = 250;
this.myCanvas = canvas;
}
}
- 然后我可以为每个段调用一个 "draw" 绘制二维路径的函数:
draw(ctx){
ctx.save();
ctx.strokeStyle="#000000";
ctx.lineWidth=2;
ctx.lineJoin="round";
ctx.font=" 10px sans-serif";
ctx.beginPath();
ctx.moveTo(158.108112514019,24.324327290058136);
ctx.lineTo(159.45946389436722,24.324327290058136);
ctx.lineTo(160.13513958454132,25.67567867040634);
...
ctx.lineTo(162.16216665506363,25.00000298023224);
ctx.fill("nonzero");
ctx.stroke();
ctx.restore();
}
我得到这样的上下文:
var ctx = this.myCanvas.getContext('2d');
我制作了一个有 13 个片段的原型。每个线段有大约 50 个节点,我一次绘制了所有 13 个线段。在我的 React Native 应用程序中,这需要将近一秒钟的时间来绘制,这太慢了(还有 90 多个片段我还没有渲染......)。如果我在 HTML canvas 和 Google Chrome 上绘制相同的路径,只需要 2-5 毫秒。
有没有人知道如何提高性能?或者是否有另一个库更适合我的目的?`
提前致谢!
感谢您发布如此详细的问题。 React Native Canvas 与 HTML canvas 相比相当慢,因为每个指令都被传送到 WebView。我能想到的一种提高性能的潜在方法是使用 Path2D 因为对象在呈现之前包含多个指令。你能试试看它是否提高了性能吗?
Iddans 的回答是正确的,因为我无法 post 作为对他的回答的评论来详细说明我们是如何解决这个问题的,我正在 post 自己一个新的答案。
正如 Iddan 所说,正确的解决方案确实是尽量减少发送到 canvas 的指令数量。
我们更改了问题的第 4 点。我们没有直接使用 ctx.lineTo(...)
语句绘制路径,而是将所有 SVG 路径提取为字符串并将它们存储在数组中:
const svgPaths = [
'M713.33,497.34a38.67 ... ',
...
]
对于每个渲染周期,我们决定要渲染所有 SVG 路径的哪个子集并将它们存储在一个新数组中,然后我们创建所有所需 svg 路径的单个 Path2D 对象
const svgPathsSubset = [svgPaths[1], svgPaths[7], ... ]
const pathToRender = new Path2D(this.myCanvas, svgPathsSubset)
const ctx = this.myCanvas.getContext('2d')
ctx.fill(pathToRender)
这非常快,只需几毫秒。