所属分类:web前端开发
React Native中怎么画图表?下面本篇文章就来给大家介绍一下怎么使用React Native+Echarts开发一个真实的电商数据统计页面,希望对大家有所帮助!
平时写图表相关需求,用得最多的图表库就是echarts。echarts 在 web 端的表现已经相当成熟,官方对小程序端也提供了解决方案,而在 RN 方面却没有相应支持。市面上搜到的,大多本质还是基于 webview 实现,而我更倾向于基于 RN 的方案,毕竟原生的体验会比 Web 的更好一些。
所以我们发布了@wuba/react-native-echarts 来满足需求。对实现原理感兴趣的可以看这里。
接下来我将使用 @wuba/react-native-echarts来做一个实际项目中的应用,截图如下:
本地搭好 RN 开发环境,搭建过程网上一抓一大把,就不赘述了。
因为是试用,所以我用 expo 新初始化了一个 rn 工程,叫 TestApp。
npx create-expo-app TestApp
登录后复制
用命令行生成包 ios android app 包。这里 ios 建议用模拟器(不需要配证书),安卓我是连的真机
yarn android
yarn ios
登录后复制
生成包后,手机看到已经安装了这个应用,就代表成功啦。
yarn add @wuba/react-native-echarts echarts
yarn add @shopify/react-native-skia
yarn add react-native-svg
登录后复制
注意,如果你是在已有工程中安装,安装完成后要重新打个新包,不然缺少原生依赖会报错;
@wuba/react-native-echarts 支持两种渲染模式(Skia 和 Svg),先用 Skia 试一个简单的图表。大致分为这几个小步骤:
具体代码如下:
import { useRef, useEffect } from 'react';
import { View } from 'react-native';
/**
* 一、引入echarts依赖,这里先试下折线图
*/
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import { GridComponent } from 'echarts/components';
import { SVGRenderer, SkiaChart } from '@wuba/react-native-echarts';
/**
* 二、注册需要用到的组件
* SVGRenderer: 是必须注册的
* LineChart: 因为用的折线图,所以要引入LineChart(如果不知道该引入哪些组件,就直接看报错,报错说缺什么就加什么)
* GridComponent: 这个就是报错的时候提示,然后我加的hhh
*/
echarts.use([SVGRenderer, LineChart, GridComponent]);
export default () => {
const skiaRef = useRef(null); // Ref用于保存图表实例
useEffect(() => {
/**
* 四、图表配置
*/
const option = {
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',
},
],
};
let chart;
if (skiaRef.current) {
/**
* 五、初始化图表,指定下宽高
*/
chart = echarts.init(skiaRef.current, 'light', {
renderer: 'svg',
width: 400,
height: 400,
});
chart.setOption(option);
}
/**
* 六、页面关闭后要销毁图表实例
*/
return () => chart?.dispose();
}, []);
return (
<View className='index'>
<SkiaChart ref={skiaRef} />
</View>
);
};
登录后复制
写完摇一摇手机,reload bundle 包时出现了报错:
ERROR Invariant Violation: requireNativeComponent: "SkiaDomView" was not found in the UIManager.
google 了一下,说是需要降级解决。其实是要跟 expo 版本对应,在安装依赖的时候也会有类似这样的提示,安装提示的版本就可以了
于是按照提示做了版本降级:
@shopify/react-native-skia@0.1.157
react-native-svg@13.4.0
登录后复制
重新构建 app 后加载出来了,针不戳;(安卓遮住了点,看来应该自适应屏幕宽度)
iOS | Android |
---|---|
写个复杂点的动态排序柱状图,试试 Svg 模式,给 Svg 和 Skia 做个对比,完整代码看这里。
// ...此处省略一些不重要的代码
// 注册需要用到的组件,BarChart-柱状图 LegendComponent-图例
echarts.use([SVGRenderer, BarChart, LegendComponent, GridComponent]);
export default () => {
const skiaRef = useRef(null);
const svgRef = useRef(null);
useEffect(() => {
// Skia模式
const skiaChartData = getData(); // 生成图表柱状图数据
let skiaChart;
let skiaInter;
if (skiaRef.current) {
skiaChart = echarts.init(skiaRef.current, 'light', {
renderer: 'svg',
width: 300,
height: 300,
});
skiaChart.setOption(getDefaultOption(skiaChartData));
setTimeout(function () {
run(skiaChart, skiaChartData);
}, 0);
skiaInter = setInterval(function () {
run(skiaChart, skiaChartData);
}, 3000);
}
// Svg模式
const svgChartData = getData();
let svgChart;
let svgInter;
if (svgRef.current) {
svgChart = echarts.init(svgRef.current, 'light', {
renderer: 'svg',
width: 300,
height: 300,
});
svgChart.setOption(getDefaultOption(svgChartData));
setTimeout(function () {
run(svgChart, svgChartData);
}, 0);
svgInter = setInterval(function () {
run(svgChart, svgChartData);
}, 3000);
}
return () => {
skiaChart?.dispose();
svgChart?.dispose();
// 定时器得清理掉,不然退出页面后还会运行
clearInterval(skiaInter);
clearInterval(svgInter);
};
}, []);
return (
<View>
<Text>skia如下</Text>
<SkiaChart ref={skiaRef} />
<Text>svg如下</Text>
<SvgChart ref={svgRef} />
</View>
);
};
登录后复制
Skia 和 Svg 模式,肉眼看不出明显差别
iOS | Android |
---|---|
效果不错,不过每次使用都要把一堆东西引进去好烦,先简单封装下吧
import { useRef, useEffect } from 'react';
import * as echarts from 'echarts/core';
import { BarChart, LineChart, PieChart } from 'echarts/charts';
import {
DataZoomComponent,
GridComponent,
LegendComponent,
TitleComponent,
ToolboxComponent,
TooltipComponent,
} from 'echarts/components';
import {
SVGRenderer,
SvgChart as _SvgChart,
SkiaChart as _SkiaChart,
} from '@wuba/react-native-echarts';
import { Dimensions } from 'react-native';
// 注册需要用到的组件
echarts.use([
DataZoomComponent,
SVGRenderer,
BarChart,
GridComponent,
LegendComponent,
ToolboxComponent,
TooltipComponent,
TitleComponent,
PieChart,
LineChart,
]);
// 图表默认宽高
const CHART_WIDTH = Dimensions.get('screen').width; // 默认用手机屏幕宽度
const CHART_HEIGHT = 300;
const Chart = ({
option,
onInit,
width = CHART_WIDTH,
height = CHART_HEIGHT,
ChartComponent,
}) => {
const chartRef = useRef(null);
useEffect(() => {
let chart;
if (chartRef.current) {
chart = echarts.init(chartRef.current, 'light', {
renderer: 'svg',
width,
height,
});
option && chart.setOption(option);
onInit?.(chart);
}
return () => chart?.dispose();
}, [option]);
return <ChartComponent ref={chartRef} />;
};
const SkiaChart = (props) => <Chart {...props} ChartComponent={_SkiaChart} />;
const SvgChart = (props) => <Chart {...props} ChartComponent={_SvgChart} />;
// 对外只暴露这哥俩就行
export { SkiaChart, SvgChart };
登录后复制
封装好了,咱就写个多图表同时使用的页面看看效果。这里写了个“电商数据分析”页面,分别有折线图、柱状图、饼图。下方是主要代码,用的 svg 模式,详细代码见这里。
// 页面代码
import { SkiaChart } from '../../components/Chart';
import { ScrollView, Text, View } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { useCallback, useEffect, useState } from 'react';
import {
defaultActual,
lineOption,
salesStatus,
salesVolume,
userAnaly,
getLineData,
} from './contants';
import styles from './styles';
// 开启图表loading
const showChartLoading = (chart) =>
chart.showLoading('default', {
maskColor: '#305d9e',
});
// 关闭图表loading
const hideChartLoading = (chart) => chart.hideLoading();
export default () => {
const [actual, setActual] = useState(defaultActual); // 记录实时数据
useEffect(() => {
// 假设循环请求数据
const interv = setInterval(() => {
const newActual = [];
for (let it of actual) {
newActual.push({
...it,
num: it.num + Math.floor((Math.random() * it.num) / 100),
});
}
setActual(newActual);
}, 200);
return () => clearInterval(interv);
}, [actual]);
const onInitLineChart = useCallback((myChart) => {
showChartLoading(myChart);
// 模拟数据请求
setTimeout(() => {
myChart.setOption({
series: getLineData,
});
hideChartLoading(myChart);
}, 1000);
}, []);
const onInitUserChart = useCallback((myChart) => {
// 模拟数据请求,跟onInitLineChart类似
}, []);
const onInitSaleChart = useCallback((myChart) => {
// 模拟数据请求,跟onInitLineChart类似
}, []);
const onInitStatusChart = useCallback((myChart) => {
// 模拟数据请求,跟onInitLineChart类似
}, []);
const chartList = [
['订单走势', lineOption, onInitLineChart],
['用户统计', userAnaly, onInitUserChart],
['各品类销售统计', salesVolume, onInitSaleChart],
['订单状态统计', salesStatus, onInitStatusChart],
];
return (
<ScrollView style={styles.index}>
<StatusBar style='light' />
<View>
<View style={styles.index_panel_header}>
<Text style={styles.index_panel_title}>实时数据</Text>
</View>
<View style={styles.index_panel_content}>
{actual.map(({ title, num, unit }) => (
<View key={title} style={styles.sale_item}>
<View style={styles.sale_item_cell}>
<Text style={styles.sale_item_text}>{title}</Text>
</View>
<View style={[styles.sale_item_cell, styles.num]}>
<Text style={styles.sale_item_num}>{num}</Text>
</View>
<View style={[styles.sale_item_cell, styles.unit]}>
<Text style={styles.sale_item_text}>{unit}</Text>
</View>
</View>
))}
</View>
</View>
{chartList.map(([title, data, callback]) => (
<View key={title}>
<View style={styles.index_panel_header}>
<Text style={styles.index_panel_title}>{title}</Text>
</View>
<View style={styles.index_panel_content}>
<SkiaChart option={data} onInit={callback} />
</View>
</View>
))}
</ScrollView>
);
};
登录后复制
重新加载 bundle,看看效果图
iOS | Android |
---|---|
渲染出来后,iOS 上交互很丝滑,安卓上交互时感觉偶尔会有卡顿(不会是因为我手机太差吧…)。
再换 Skia 模式看看
emmm 虽然可以,但是好像中文不能正常显示,安卓上中文都没有显示,iOS 则是乱码。看了下文档,目前 skia 在安卓端还不支持中文,在 iOS 端可以通过设置字体为 'PingFang SC'显示中文,比如:
const option = {
title: {
text: '我是中文',
textStyle: {
fontFamily: 'PingFang SC', // 指定字体类型
},
},
};
登录后复制
但是每个显示中文的地方都要设置字体……那还是先用 svg 吧,我懒。
使用了一段时间后,我总结了下:
(学习视频分享:vuejs入门教程、编程基础视频)
以上就是聊聊React Native中怎么利用echarts画图表的详细内容,更多请关注zzsucai.com其它相关文章!