我司的一个心率图需求 :
每5分钟采一个点,那么一天1440分钟,大概会有288个数据点, 所以在app上基本就是1dp 对应 1个数据点,看起来密密麻麻的,使用静态图表展示确实不够友好,这种情况下原本 react-native-svg-charts 这个库就无法满足需求了。
这个时候我有两个选择 :
- 使用第三方库
- 基于 `svg + d3` 手撸一个
项目中是自己手撸的,在iphone6下还是比较卡顿,那低端安卓机就不用讲了,能优化的都优化了,尽力了。
最近空下来。就试着尝试用 victory-native 这个库实现了一遍
先来介绍下这个库吧,从这个库的官网来看,是一个叫 FormidableLabs 的组织,开源了web端的基于svg实现的react图表库,该库能够交互式动态展现图表,可以说功能非常强大,然后他们在此基础上又推出了react-native的兼容版,强大之处就是缩放类功能完美移植。
最终效果图
简单来说,用victory-native构建一个图表
1、第一步就是用 VictoryChart包裹
{...}
2、要实现缩放,那么第二步则是
minDomain={{ x: 0 }}
maxDomain={{ x: 1440 }}
containerComponent={
zoomDimension="x"
onZoomDomainChange={this.handleDomainChange}
zoomDomain={{ x: xDomain, y: yDomain }}
minimumZoom={minimumZoom}
clipContainerComponent={
clipPadding={{ top: 10, right: 10, bottom: 10, left: 10 }}
/>
}
onTouchStart={(evt) => {
this.locationX = evt.nativeEvent.locationX;
}}
/>
}
>
{...children...}
说明
1、VictoryChart的 minDomain 和 maxDomain 一定要指定因为它能够确定图表最大的Domain
在数据点为空的情况下也能按正常情况缩放
2、容器指定为 VictoryZoomContainer
zoomDimension 指定需要缩放的轴系
onZoomDomainChange 缩放过程的响应回调
zoomDomain 指定图表初始显示的x轴和y轴 范围
minimumZoom 指定缩放的最小间距
clipContainerComponent 由于标记数据点可能被默认ClipPath
截断,所以根据自身情况添加一定 clipPadding使图表完全展现
onTouchStart 触摸开始的回调,可以用于实现自定义 tip
3、有了事件响应容器之后,就需要添加 X轴 和 Y轴
containerComponent={
}
>
axisComponent={} />}
tickFormat={this.xTickFormat}
style={{
grid: {
stroke: 'gray',
strokeDasharray: '5 5',
},
}}
/>
dependentAxis
axisComponent={} />}
style={{
grid: {
stroke: 'gray',
strokeDasharray: '5 5',
},
}}
/>
{...children...}
说明
1、由于 VictoryAxis 的 tickValues 官方默认只接受 数组 类型
则需要添加 WrapperComponent 接受一个函数来自定义 轴 的label 显示
2、若想不显示坐标系的坐标线,需要将axisComponent的LineSegment的lineComponent置为 ()=>null 的组件
3、通过style.grid来设置网图的样式,符合svg标准
4、dependentAxis ture表示Y轴,false表示X轴
4、添加曲线以及渐变色之后
containerComponent={
}
>
data={this._data}
interpolation="monotoneX"
style={{
data: {
stroke: lineColor,
strokeWidth: lineStroke,
fill: LinearGradient.fill,
},
}}
/>
data={this._data}
style={{ data: { stroke: lineColor, fill: lineColor } }}
/>
{...children...}
说明
1、添加一个LinearGradient 产生渐变效果,符合svg标准
2、interpolation monotoneX 曲线方式连接点,没有偏差
3、Area用来产生曲线以及下边沿的背景色,Scatter用于生成对应点
5、添加一个自定义的指示控件
containerComponent={
}
>
说明
自定义实现一个 指示控件,具体实现方式可以滑到 本文最后 github的demo地址
最终的总体结构是这样的
minDomain={{ x: 0 }}
maxDomain={{ x: 1440 }}
containerComponent={
zoomDimension="x"
onZoomDomainChange={this.handleDomainChange}
zoomDomain={{ x: xDomain, y: yDomain }}
minimumZoom={minimumZoom}
clipContainerComponent={
clipPadding={{ top: 10, right: 10, bottom: 10, left: 10 }}
/>
}
onTouchStart={(evt) => {
this.locationX = evt.nativeEvent.locationX;
}}
/>
}
>
axisComponent={} />}
ickFormat={this.xTickFormat}
style={{
grid: {
stroke: 'gray',
strokeDasharray: '5 5',
},
}}
/>
dependentAxis
axisComponent={} />}
style={{
grid: {
stroke: 'gray',
strokeDasharray: '5 5',
},
}}
/>
data={this._data}
interpolation="monotoneX"
style={{
data: {
stroke: lineColor,
strokeWidth: lineStroke,
fill: LinearGradient.fill,
},
}}
/>
data={this._data}
style={{ data: { stroke: lineColor, fill: lineColor } }}
/>
this} />
尝试了一番,在iphone6下还是卡顿,所以我之前手撸的纯js控件是真的尽力了。感觉是这个js回调机制还是耗能,对低端设备有高要求的同学还是手撸一个定制化原生控件,封装给RN层傻瓜式调用吧
对于victoryNative这个库的槽点就是文档偏少,官方给的案例都带点 案例仅供参考的感觉,上起手来偏生硬吧。不过确实是RN端图表类的一个解决方案。
以前看别人的博文,行云流水一气呵成,从来没考虑过会花多少时间,而当自己真心去总结的时候发现,篇幅再短可能都不止1个小时。
愿明天是 新的一天,大步走向前。─=≡Σ(((つ•̀ω•́)つ