echarts渲染过程中-开源 | wrn-echarts:在 RN 中使用 ECharts

2023-08-23 0 8,053 百度已收录

记录

一、背景

2、可行性分析

三、原理与实现

4、项目中如何使用

5. 真机演示

6、方案对比

七、总结与规划

本文主要介绍wrn-echarts项目。 接下来,本文将从诞生背景、设计实现、效果演示等方面向大家详细介绍该项目。

01

背景

在日常的业务需求开发中,我们经常会遇到需要绘制图表的场景。 其中,我们最常使用的图表库是ECharts[1]。 ECharts作为市面上最成熟的图表库之一,主要面向Web端,官方也为小程序端提供了解决方案,但在RN开发场景下还没有更好的实现方法。 面对这些情况,我们常用的解决方案是:

1.放弃ECharts,使用原生为RN开发的图表库,如react-native-charts-wrapper、victory-native等。

2.通过Webview使用Web端ECahrts,如react-native-echarts-pro[2]、native-echarts等。

方案一,RN现有图表库的风格和交互与ECahrts差异较大,图表丰富度不够,尤其是多终端需求的场景,需要为RN单独设计UI交互,并且设计和实施成本高。

方案二,通过Webview的方法,当页面上有多个图表或者图表元素过多时,会遇到性能困难。 比如Android端的大数据面积图、单轴散点图会崩溃。 并且在正常渲染过程中,会出现比较明显的卡顿、掉帧的情况。

因此,我们希望开发一个图表库,可以利用RN原生的渲染控件,将Web ECharts的能力集成到RN应用中,以提高开发效率和不同平台上产品体验的一致性,同时实现真正的跨端图表为我们以后的图书馆打下基础。

02

可行性分析

既然要使用RN原生渲染,首先看一下RN当前支持的图形库:

react-native-svg[3]:提供了可以在RN中使用的基本SVG图形库。 该库通过类似于Web端的SVG渲染模式来渲染图形(该方案以下简称WRNSVG模式)

react-native-skia[4]:Skia[5]是一个跨平台的图形渲染引擎。 该库将Skia的2d图形库引入到RN中,同时还提供了一个ImageSVG组件,支持SVG格式图像的渲染(此方案以下简称WRNSkia模式)

据分析,上述两种方案实现的核心都是获取ECharts图表的SVG图形数据。 而且我们知道ECharts本身就支持SVG格式的渲染,所以我们去ECharts代码仓库查看相关实现,看看能否得到我们想要的数据。

查看源码时我们发现这部分功能是通过调用zrender[6]库的SVGPainter组件来实现的,而我们可以通过修改渲染组件来获取图表的SVG图形数据,所以我们的解决方案是可行的。 并且由于WRNSVG模式和WRNSkia模式两种方案的核心流程相似,因此我们计划同时支持两种实现方式,以便用户选择适合自己的一种。

03

原理与实现

1、架构设计

2、核心流程

以WRNSVG模式为例,核心工作流程为:

2.1 替换ECharts的SVGRenderer,将注册的SVGPainter替换为自定义的CustomSVGPainter

2.2 CustomSVGPainter继承自SVGPainter,并重写了构造函数和刷新函数的部分实现。 当图表数据初始化或更新时,它会调用在 SVGComponent 上注册的 patch 函数,并将估计的新 SVG 数据传递给它。

2.3 定义SVGComponent,它管理当前图表实例,有一个核心补丁函数,用于接收实时SVG数据,然后调用SVGElement函数

2.4 SVGElement函数遍历SVG的所有节点,转换为react-native-svg提供的对应SVG元素进行最终渲染

与WRNSkia模式的区别:

与WRNSVG模式相比,WRNSkia模式的整体流程相对简单。 定义的SkiaComponent组件上有一个核心技能patchString。 PatchString接收变化后的SVG数据,合并转换为SVG图片格式数据,传递给react-native-skia的ImageSVG组件进行整体渲染

3.处理TouchEvent(手势干扰)

Web ECharts的动作就是键盘动作,比如click、dblclick、mousedown、mousemove等,通过键盘动作触发图表元素的显示或动画。 RN ECharts 需要将移动端的 TouchEvent 模拟为键盘风暴,并调度到 ECharts init 方法生成的图表实例中。

例如跟随键盘在图表上显示图例的动作对应移动端的TouchStart + TouchMove,键盘上的mousedown + mousemove。 还有图表等缩放。 移动端是用两指按下并缩放,将对应的鼠标滚轮事件转换为键盘的鼠标滚轮事件,通过两指距离的变化来估计对应的鼠标滚轮滚动距离。

关键代码:

1)将TouchEvent转换为MouseEvent

// ...PanResponder.create({  onPanResponderGrant: ({ nativeEvent }) => {    // 动作开始,在这里转化为鼠标的点击与移动事件    dispatchEvent(      zrenderId,      ['mousedown', 'mousemove'],      nativeEvent,      'start'    );  },  onPanResponderMove: ({ nativeEvent }) => {    // 处理手指移动操作    const length = nativeEvent.touches.length;    if (length === 1) {      // 在这里处理单指移动操作...    } else if (length === 2) {      // 在这里处理双指移动操作...      if (!zooming) {        // ...      } else {        // 在这里转化为滚轮的事件        const { initialX, initialY, prevDistance } = pan.current;        const delta = distance - prevDistance;        pan.current.prevDistance = distance;        dispatchEvent(zrenderId, ['mousewheel'], nativeEvent, undefined, {          zrX: initialX,          zrY: initialY,          zrDelta: delta / 120,        });      }    }  },  onPanResponderRelease: ({ nativeEvent }) => {    // 动作结束,在这里转化为鼠标点击释放操作...  },}),

2)将MouseEvent应用到ECharts图表实例上

function dispatchEvent(  zrenderId: number,  types: HandlerName[],  nativeEvent: NativeTouchEvent,  stage: 'start' | 'end' | 'change' | undefined,  props: any = {    zrX: nativeEvent.locationX,    zrY: nativeEvent.locationY,  }) {  if (zrenderId) {    var handler = getInstance(zrenderId).handler;    types.forEach(function (type) {      handler.dispatch(type, {        preventDefault: noop,        stopImmediatePropagation: noop,        stopPropagation: noop,        ...props,      });      stage && handler.processGesture(wrapTouch(nativeEvent), stage);    });  }}

四、问题及解决方案

内部流程开发完成后,我们首先用基本的简单图表进行测试,然后开始对ECharts的各种图表类型进行对比测试。 在测试过程中,我们发现并处理了很多图表显示的异常情况,例如:

echarts渲染过程中-开源 |  wrn-echarts:在 RN 中使用 ECharts

4.1 WRNSkia模式下英文乱码

我们发现在WRNSkia模式下渲染时,图表中的英文字符显示为乱码。 为什么会出现乱码? 首先我们猜测是字体有问题。 查看字体文件信息,没有英文字体。 检查react-native-skia。 原因是不支持字体回退(字体回退:字符串中的各个字符不受当前字体的影响。当支持时,它回退到检索字体队列中支持的字体)。

于是我们找到了一个英文字体文件Skia.Typeface.MakeFreeTypeFaceFromData,在运行时导出,此时就可以正常显示了。 但此时我们也考虑到不同系统上使用的字体是不同的。 英文字体文件非常大,我们无法导出所有种类的字体。 但如果只提供一种字体,体验肯定会不友好。 那么我们可以直接使用系统自带的英文字体吗?

于是我们考察了iOS和Android支持的英文字体,最后我们决定,当有英文文本设置时,Android设置font-family使用Noto Sans,iOS使用PingFang SC。

4.2 字体重叠和空白

中文乱码问题解决后,我们发现英文存在字体重叠问题。 我们猜测是字体长度的估计有问题,因为英文是等宽字体,所以没有问题。

查看zrender的measureText实现,其中在svgrender中将字体写为sans-serif,并根据这个字体估计一个长度,如果其他字体长度超过,就会出现重叠,如果设置的字体长度为小了,就会有空白。

所以我们把这部分改成使用Noto Sans和PingFang SC来估计长度并解决了。

04

项目中如何使用

实际应用中,wrn-echarts的整体流程与ECharts类似:

1.根据使用的渲染方式,选择安装react-native-svg或@shopify/react-native-skia

2.安装wrn-echarts并引入相关组件

3、将ECharts的SVGRenderer替换为wrn-echarts的SVGRenderer

4.写入图表的选项配置信息

5.使用SkiaChart/SvgChart组件

例子

从'echarts/core'导入*作为echarts; 从 'react' 导入 { useEffect, useRef }; 从 'wrn-echarts' 导入 { SVGRenderer, SvgChart };

// 注册必要的组件 echarts.use([ SVGRenderer, // 这里SVGRenderer是wrn-echarts的SVGRenderer]);

export default function EchartsPage() { // svgRef 用于保存图表实例 const svgRef = useRef(null); // 编写图表配置文件(示例) const option = { xAxis: {type: 'category', data: ['Mon ', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '太阳'] }, yAxis: {type: 'value' }, 系列: [{data: [150, 230, 224 , 218, 135, 147, 260],type: 'line'} ] };

useEffect(() => { let Chart; if (svgRef.current) {//图表初始化 Chart = echarts.init(svgRef.current, 'light', {renderer: 'svg',width: 300,height: 300} );chart.setOption(option); } return () => Chart?.dispose(); }, []);

返回

过去一段时间,我们进行了大量的测试,尝试了各种类型的图表,修复了很多存在的问题。 目前我们已经支持了ECharts支持的大部分图表。

echarts渲染过程中-开源 |  wrn-echarts:在 RN 中使用 ECharts

下面我展示一些真机效果图,更多示例可以在项目上查看

例子

06

方案对比

正如之前背景中提到的,我们的目标场景是在RN端使用ECharts。 目前主流的方案都是通过WebView来实现的,而在众多基于WebView的实现中,react-native-echarts-pro的用户也比较多,所以我们选择react-native-echarts-pro作为对照进行对比测试。

该工具使用“火山引擎”[7]进行性能评估。 使用华为nova5Pro作为测试机。 测试时使用svg、skia、react-native-echarts-pro绘制同一张图表,并记录图表从初始化到渲染完成的时间段。 各种性能数据的平均值,每次采样20次; 性能指标包括整机CPU使用率、App CPU使用率、平均FPS(去掉零位)、JavaHeap、NativeHeap、Code、Graphics、Other、System、以及卡顿次数、占比冻结时间等

部分核心指标对比数据如下:

1、不同类型内存使用情况对比

单表数据量较大的情况:

当同时渲染多个图表时:

比较结果:

JAVA模块:在渲染单表大量数据时,WRNSVG模式总体优于其他两种。 同时渲染多个表格时,WRNSkia 和 WRNSVG 渲染模式均明显优于react-native-echarts-pro方案。

Native模块:这个数据在不同场景下的推断是一致的,WRNSVG模式比其他两种方案稍好一些。

图形渲染模块:同时渲染多个图表时,WRNSkia和WRNSVG两种渲染模式总体优于react-native-echarts-pro方案。

2、整机CPU占用率对比

echarts渲染过程中-开源 |  wrn-echarts:在 RN 中使用 ECharts

单表数据量较大的情况:

当同时渲染多个图表时:

对比结果:对比数据显示,不同情况下WRNSkia和WRNSVG两种模式在整体CPU占用率上均略优于react-native-echarts-pro方案。

3.FPS平均对比(数值越高越好)

单表数据量较大的情况:

当同时渲染多个图表时:

对比结果:对比数据显示,react-native-echarts-pro方案在屏幕刷新频率方面比较稳定,整体略优于该方案提供的两种模式。 WRNSVG 模式的分辨率低于 WRNSkia 模式。 稳定下来。

4、其他

除了上面列出的对比数据外,在图表初始化过程中,react-native-echarts-pro方案的整体屏幕渲染速度相对较慢。 看下面的动画你可以直观地感受到差异:

5. 对比总结

下表总结了比较数据。 以react-native-echarts-pro方案为基准,评分为3分,以1-5分的等级来评估不同指标下各种形态的表现。 分数越高echarts渲染过程中,性能越好:

从表对比可以看出,WRNSVG模式综合性能最好,其次是WRNSkia模式。 这两种方案在与显存相关的各项指标上都不同程度地优于react-native-echarts-pro方案。 与react-native-echarts-pro方案相比,在FPS指标上有一定的劣势。 请根据实际情况选择适合您的方案和渲染模式。

07

总结与规划

以上就是我们wrn-echarts从规划、设计到实施的大概流程。

事实上,这个过程并非一帆风顺。 例如,我们最初想在RN上实现一个与Web上的canvas一模一样的canvas2d上下文,但经过实验,我们发现这些方法实现起来太复杂了。 虽然我们已经可以做简单的图形了,但是光是实现一部分API就耗费了我们很大的精力,所以我们放弃了这个方向,重新开始思考。

最终我们找到了这些方法,绕过底层socket的实现,而是充当中间人,充分利用现有的轮子,提供了这些在RN上使用ECharts的新形式。

echarts渲染过程中-开源 |  wrn-echarts:在 RN 中使用 ECharts

后续规划:

1.实现WRNSkia的Canvas渲染模式:

除了提供ImageSVG组件外,re​​act-native-skia还提供了可以在RN中使用的Canvas基础图形组件,因为现有的WRNSkia模式和WRNSVG模式在面对大数据时,在内存占用和渲染效率方面表现良好。数据处理量并不大,所以我们期待在实现WRNSkia的Canvas渲染模式时能在这方面有所改进。

2、打包taro-echarts:

将wrn-echarts与各端其他图表实现方案进行整合,打包为taro-echarts库,使得Taro可以实现跨端开发中图表相关的需求(Taro:开源跨端跨框架解决方案,支持利用后端脚本句型来开发Web、小程序、原生应用等应用,实现一套代码在多个终端上运行)。

wrn-echarts项目现已开源,项目地址,欢迎star。

另外,本文的示例代码是在项目上的echarts渲染过程中,仓库也是开源的。 感兴趣的朋友还可以直接从应用商店安装新版太郎游乐场应用来体验。

使用过程中,如果遇到任何问题,可以加“58技术秘书”或“太郎助理”为好友,备注“太郎RN”,加入官方交流群寻求帮助。

相关链接:

[1] 电子图表:

[2]react-native-echarts-pro:

[3] 反应本机滑雪:

[4]斯基亚:

[5]react-native-svg:

[6] 渲染:

[7] 火山引擎:

关于作者:

李志浩:58同城高级前端开发工程师

谢谢:

陈志清:方案设计及核心模块开发

杨阳:提供测试用例和测试数据

王新建:图表显示问题修复

袁津津:图表Demo整理

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 echarts echarts渲染过程中-开源 | wrn-echarts:在 RN 中使用 ECharts https://www.wkzy.net/game/148532.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务