当前位置: 首页 > Web前端 > JavaScript

wrn-echarts-在RN中使用ECharts

时间:2023-03-27 14:03:12 JavaScript

本文主要介绍wrn-echarts项目。接下来,本文将从诞生背景、设计实现、效果演示等方面详细介绍该项目。官网:https://wuba.github.io/wrn-ec...源代码:https://github.com/wuba/wrn-e...背景在日常的业务需求开发中,我们经常会遇到需要绘制图表的场景,其中我们使用频率最高的图表库是ECharts。ECharts作为市面上最成熟的图表库之一,主要用于Web端。官方也为小程序端提供了解决方案。但是在RN开发场景下,目前还没有更好的实现方式。面对这种情况,之前我们的解决方案是:放弃ECharts,使用原生为RN开发的图表库,如react-native-charts-wrapper、victory-native等。通过Webview使用web端的ECahrts,如react-native-echarts-pro,native-Scheme1比如echarts,RN现有的图表库在风格和交互方面远远落后于ECahrts,图表的丰富度也有所不足。尤其是在有多种需求的场景下,需要单独为RN设计UI交互。实施成本很高。方案二,通过Webview,当页面有多个图表或图表元素过多时,会遇到性能瓶颈。比如Android端的大数据面积图、单轴散点图都会出现白屏。而且在正常渲染过程中会有比较明显的卡顿和掉帧现象。因此,我们希望开发一个可以使用RN原生渲染控件的图表库,将WebECharts的能力集成到RN应用中,以提高开发效率和不同平台产品体验的一致性,同时实现真正的跨端图表为我们以后建库打下基础。可行性分析既然要使用RN原生渲染,首先看一下RN目前支持的图形库:react-native-svg:提供了一个可以在RN中使用的基础SVG图形库,类似于上的SVG渲染模式网络。渲染图形(本方案以下简称WRNSVG模式)react-native-skia:Skia是一个跨平台的图形渲染引擎。这个库在RN中引入了Skia的2d图形库,同时也提供了一个支持SVG格式图片的ImageSVG组件,根据渲染分析(以下简称本方案中的WRNSkia模式),以上两种方案的实现核心是获取ECharts图表的SVG图形数据。而我们知道ECharts本身是支持SVG格式的渲染的,所以我们去ECharts代码仓库查看相关的实现,看看能不能拿到我们想要的数据。查看源码发现这部分功能是通过调用zrender库的SVGPainter组件实现的,我们可以通过修改渲染组件获取图表的SVG图形数据,所以我们的方案是可行的。并且由于WRNSVG模式和WRNSkia模式这两种方案的核心流程相似,我们计划同时支持这两种实现方式,让用户可以选择适合自己的。原理及实现1.架构设计2.核心流程以WRNSVG模式为例,核心流程为:替换ECharts的SVGRenderer,将注册的SVGPainter替换为自定义的CustomSVGPainterCustomSVGPainter继承自SVGPainter,重写了构造函数和刷新函数的一部分实现,当图表数据初始化或更新时,调用注册在SVGComponent上的patch函数,将计算出的新SVG数据传递给定义SVGComponent,SVGComponent管理当前图表实例,有一个核心patch函数用于接收实时SVG数据,然后调用SVGElement函数。SVGElement函数遍历SVG的所有节点,将其转化为react-native-svg提供的对应的SVG元素进行最终渲染。与WRNSkia模式的区别:WRNSkia模式整体流程比WRNSVG模式简单,在定义的SkiaComponent组件上有一个核心方法patchString,patchString接收变化的SVG数据,合并转换成SVG图像格式数据,传递给用于整体渲染的react-native-skia的ImageSVG组件。3、处理TouchEvent(手势事件)WebECharts事件是鼠标事件,如click、dblclick、mousedown、mousemove等,通过鼠标事件触发图表元素的显示或动画。RNECharts需要将移动端的TouchEvent模拟为鼠标事件,派发给EChartsinit方法生成的图表实例。比如跟随鼠标在图表上显示图例的动作对应的是移动端的TouchStart+TouchMove,mousedown+mousemove对应的是鼠标事件。另一个例子是图表的缩放。移动端是两指按下缩放,对应的mousewheel事件转化为鼠标的mousewheel事件,通过两指距离的变化计算对应的mousewheel滚动距离。关键代码:ConvertTouchEventtoMouseEvent//...PanResponder.create({onPanResponderGrant:({nativeEvent})=>{//动作开始,这里转换成鼠标点击和移动事件dispatchEvent(zrenderId,['mousedown','mousemove'],nativeEvent,'start');},onPanResponderMove:({nativeEvent})=>{//处理手指移动constlength=nativeEvent.touches.length;if(length===1){//在这里处理单指移动...}elseif(length===2){//在这里处理两指移动...if(!zooming){//...}else{//这里它转化为滚轮的事件const{initialX,initialY,prevDistance}=pan.current;constdelta=distance-prevDistance;pan.current.prevDistance=distance;dispatchEvent(zrenderId,['mousewheel'],nativeEvent,undefined,{zrX:initialX,zrY:initialY,zrDelta:delta/120,});}}},onPanResponderRelease:({nativeEvent})=>{//动作结束,这里转化为鼠标点击和释放操作...},}),将MouseEvent应用到ECharts图表实例函数dispatchEvent(zrenderId:number,types:HandlerName[],native事件:NativeTouchEvent,阶段:'开始'|'结束'|'改变'|undefined,props:any={zrX:nativeEvent.locationX,zrY:nativeEvent.locationY,}){if(zrenderId){varhandler=getInstance(zrenderId).handler;}types.forEach(function(type){handler.dispatch(type,{preventDefault:noop,stopImmediatePropagation:noop,stopPropagation:noop,...props,});stage&&handler.processGesture(wrapTouch(nativeEvent),stage);});}}4。问题及解决方案以上流程开发完成后,我们先用基本的简单图表进行测试,然后开始对比测试ECharts的各种图表类型。在测试过程中,我们发现并处理了很多图表显示的异常,例如:4.1WRNSkia模式下的中文乱码我们发现在WRNSkia模式下渲染时,图表显示的汉字是乱码。他们为什么乱码?首先我们猜测是字体有问题。查看字体文件信息,没有中文字体。检查反应本机滑雪。原因是fontfallbackisnotsupported(fontfallback:字符串中的某些字符在当前字体中不可用。支持时回退到在字体队列中检索支持的字体)。于是我们找到一个中文字体文件Skia.Typeface.MakeFreeTypeFaceFromData,在运行时导入,这时候就可以正常显示了。但是这个时候我们也考虑到不同系统使用的字体是不一样的。一个中文字体文件很大,我们不可能把所有的字体都导入进去。但是,如果只提供一种字体,体验肯定不友好。那我们是不是可以直接使用系统自带的中文字体呢?所以我们研究了iOS和Android支持的中文字体,最后我们决定在有中文文本设置的时候,Android设置font-family使用NotoSans,iOS使用PingFangSC。4.2字体重叠和空格中文乱码问题解决后,我们发现出现了英文字体重叠的问题。我们猜测是字体宽度的计算有问题,因为中文是等宽字体,所以没有问题。查看zrender的measureText实现,字体在svgrender中写成sans-serif,根据这个字体计算出一个宽度。如果其他字体的宽度超过,就会出现重叠。如果字体宽度小,就会出现空白。所以我们把这部分改成使用NotoSans和PingFangSC来计算宽度,解决了。项目中如何使用在实际应用中,wrn-echarts的整体流程与ECharts类似:根据使用的渲染方式,选择安装react-native-svg或@shopify/react-native-skia来安装wrn-echarts并引入相关组件使用wrn-echarts的SVGRenderer替换ECharts的SVGRenderer写入图表选项配置信息使用SkiaChart/SvgChart组件示例import*asechartsfrom'echarts/core';import{useEffect,useRef}from'react';import{SVGRenderer,SvgChart}from'wrn-echarts';//注册必要的组件echarts.use([SVGRenderer,//这里的SVGRenderer是wrn-echarts的SVGRenderer]);exportdefaultfunctionEchartsPage(){//svgRef用于保存图表实例constsvgRef=useRef(null);//编写图表配置文件(示例)constoption={xAxis:{type:'category',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun']},yAxis:{type:'value'},series:[{data:[150,230,224,218,135,147,260],type:'line'}]};useEffect(()=>{letchart;if(svgRef.current){//图表初始化chart=echarts.init(svgRef.current,'light',{渲染器:'svg',宽度:300,高度:300});chart.setOption(选项);}return()=>chart?.dispose();},[]);return;}运行效果的真机演示已经进行了一段时间,我们进行了大量的测试,尝试了各种类型的图表,修复了很多存在的问题。目前,ECharts支持的大部分图表已经支持。下面我将展示一些真机效果图。更多示例可以查看https://github.com/wuba/taro-...项目上的示例方案比较之前在后台提到过,我们的目标场景是在RN端使用ECharts。目前主流的方案都是通过WebView来实现的,而在众多基于WebView的实现中,react-native-echarts-pro的使用人群较多,所以我们选择了react-native-echarts-pro作为对照,使用echarts-pro进行对比测试。该工具使用“火山引擎”进行性能评估。华为nova5Pro作为测试机。测试时使用svg、skia、react-native-echarts-pro绘制同一张图表,取图表从初始化到渲染完成的性能。平均数据,每类20个样本;性能指标包括机器CPU使用率、AppCPU使用率、FPS平均值(去掉零值)、JavaHeap、NativeHeap、Code、Graphics、Other、System、卡顿次数、卡顿时长比例等,部分核心指标对比数据如下如下:1.不同类型内存占用对比单表数据量大的情况:同时渲染多张图表的情况:对比结果:JAVA模块:WRNSVG模式普遍优于其他两个在单个表中呈现大量数据时。在进行多表同时渲染时,WRNSkia和WRNSVG两种渲染方式都明显优于react-native-echarts-pro方案。Nativemodule:这个数据的结论在不同场景下是一致的,WRNSVG模式比其他两种方案稍微好一些。图形渲染模块:同时渲染多个图表时,WRNSkia和WRNSVG这两种渲染方式整体上优于react-native-echarts-pro方案。2.整机CPU占用对比单表数据量大的情况:同时渲染多个图表的情况:对比结果:对比数据显示WRNSkia和WRNSkia两种模式WRNSVG在不同情况下在整机react-native-echarts-pro解决方案的CPU占用上略胜一筹。3.FPS平均值对比(数值越高越好)单表数据量大的情况下:多图表同时渲染的情况下:对比结果:对比数据表明react-native-echarts-pro方案在屏幕刷新率方面是最好的,比较稳定,整体略好于该方案提供的两种模式。其中,WRNSVG模式的帧率比WRNSkia模式的帧率更不稳定。4.其他除了上面列出的对比数据外,在图表初始化过程中,react-native-echarts-pro方案的整屏渲染速度比较慢。看下面的动图就可以直观的感受到区别:五、对比下表是对比数据的总结。以react-native-echarts-pro方案为基准3分,按照1-5分评价各种方法在不同指标下的表现。得分越高,性能越好:从表比较可以看出,WRNSVG模式的整体性能最好,其次是WRNSkia模式。这两个方案在内存相关的各项指标上都优于react-native-echarts-pro。与react-native-echarts-pro方案相比,在FPS指标上存在一定的劣势。请根据实际情况选择适合自己的解决方案和渲染模式。总结与规划以上就是我们wrn-echarts从规划、设计到实现的大致流程。事实上,这个过程并非一帆风顺。比如我们一开始想在RN上实现一个和web上canvas一模一样的canvas2dcontext,但是经过实验发现这个方法实现起来太复杂了,虽然我们已经可以做简单的图形绘制了,但是仅仅实现一部分API就耗费了我们很多精力,所以我们放弃了这个方向,重新开始思考。最终我们找到了这种方式,绕过底层接口的实现,作为中间人,充分利用已有的轮子,提供了一种全新的EChartsonRN使用方式。后续计划实现WRNSkia的Canvas渲染模式:react-native-skia除了提供ImageSVG组件外,还提供了RN中可以使用的Canvas基础图形组件,因为现有的WRNSkia模式和WRNSVG模式都面临着大量的数据处理、内存占用和渲染效率都不是很好,所以我们期待WRNSkia的Canvas渲染模式实现后,这些方面的性能会有所提升。taro-echarts的封装:将wrn-echarts与其他各端图表实现方案进行整合,打包为taro-echarts库,实现taro在跨端开发中实现图表相关需求(Taro:开源cross-端跨框架解决方案,支持使用前端脚本语法开发Web、小程序、原生应用等应用,实现一套代码多终端运行)。wrn-echarts项目现已开源,项目地址为https://github.com/wuba/wrn-e...,欢迎star。更多内容可以查看官网https://wuba.github.io/wrn-ec...。另外,本文的示例代码在https://github.com/wuba/taro-...项目上。这个仓库也是开源的。感兴趣的同学也可以直接从应用商店安装新版太郎游乐场应用。去体验。在使用过程中,如果遇到问题,可以加“58技术小秘书”或“芋头小助手”为好友,备注“芋头RN”,加入官方交流群寻求帮助。作者简介李志浩:58同城高级前端开发工程师致谢陈志清:方案设计及核心模块开发杨洋:提供测试用例及测试数据王新建:图表显示问题修复袁津津:图表Demo整理