React Native下基于victory-native实现可缩放图表

我司的一个心率图需求 :
  每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包裹

<VictoryChart>
    {...}
</VictoryChart>

2、要实现缩放,那么第二步则是


<VictoryChart
    minDomain={{ x: 0 }}
    maxDomain={{ x: 1440 }}
    containerComponent={
         <VictoryZoomContainer
            zoomDimension="x"
            onZoomDomainChange={this.handleDomainChange}
            zoomDomain={{ x: xDomain, y: yDomain }}
            minimumZoom={minimumZoom}
            clipContainerComponent={
                        <VictoryClipContainer
                                    clipPadding={{ top: 10, right: 10, bottom: 10, left: 10 }}
                        />
            }
            onTouchStart={(evt) => {
                        this.locationX = evt.nativeEvent.locationX;
            }}
         />
    }
>
    {...children...}
</VictoryChart>

说明
1、VictoryChart的 minDomain 和 maxDomain 一定要指定因为它能够确定图表最大的Domain
  在数据点为空的情况下也能按正常情况缩放
2、容器指定为 VictoryZoomContainer
  zoomDimension 指定需要缩放的轴系
  onZoomDomainChange 缩放过程的响应回调
  zoomDomain 指定图表初始显示的x轴和y轴 范围
  minimumZoom 指定缩放的最小间距
  clipContainerComponent 由于标记数据点可能被默认ClipPath
    截断,所以根据自身情况添加一定 clipPadding使图表完全展现
  onTouchStart 触摸开始的回调,可以用于实现自定义 tip

3、有了事件响应容器之后,就需要添加 X轴 和 Y轴

<VictoryChart
    containerComponent={
        <VictoryZoomContainer />
    }
>
    <AxisWrapper tickValues={this._tickValues}>
        <VictoryAxis
            axisComponent={<LineSegment lineComponent={<NoopComponent />} />}
            tickFormat={this.xTickFormat}
            style={{
                grid: {
                    stroke: 'gray',
                    strokeDasharray: '5 5',
                },
            }}
        />
    </AxisWrapper>
    <VictoryAxis
        dependentAxis
        axisComponent={<LineSegment lineComponent={<NoopComponent />} />}
        style={{
            grid: {
                    stroke: 'gray',
                    strokeDasharray: '5 5',
                }, 
            }}
      />
    {...children...}
</VictoryChart>

说明
1、由于 VictoryAxis 的 tickValues 官方默认只接受 数组 类型
  则需要添加 WrapperComponent 接受一个函数来自定义 轴 的label 显示
2、若想不显示坐标系的坐标线,需要将axisComponent的LineSegment的lineComponent置为 ()=>null 的组件
3、通过style.grid来设置网图的样式,符合svg标准
4、dependentAxis ture表示Y轴,false表示X轴

4、添加曲线以及渐变色之后

<VictoryChart
    containerComponent={
        <VictoryZoomContainer />
    }
>
    <VictoryAxis />
    <VictoryAxis dependentAxis />
    <LinearGradient />
    <VictoryArea
        data={this._data}
        interpolation="monotoneX"
        style={{
            data: {
                stroke: lineColor,
                strokeWidth: lineStroke,
                fill: LinearGradient.fill,
            },
        }}
    />
    <VictoryScatter
        data={this._data}
        style={{ data: { stroke: lineColor, fill: lineColor } }}
    />
    {...children...}
</VictoryChart>

说明
1、添加一个LinearGradient 产生渐变效果,符合svg标准
2、interpolation monotoneX 曲线方式连接点,没有偏差
3、Area用来产生曲线以及下边沿的背景色,Scatter用于生成对应点

5、添加一个自定义的指示控件

<VictoryChart
    containerComponent={
        <VictoryZoomContainer />
    }
>
    <VictoryAxis />
    <VictoryAxis dependentAxis />
    <LinearGradient />
    <VictoryArea />
    <VictoryScatter />
    <CustomIndicator />
</VictoryChart>

说明
自定义实现一个 指示控件,具体实现方式可以滑到 本文最后 github的demo地址

最终的总体结构是这样的

<VictoryChart
    minDomain={{ x: 0 }}
    maxDomain={{ x: 1440 }}
    containerComponent={
        <VictoryZoomContainer
            zoomDimension="x"
            onZoomDomainChange={this.handleDomainChange}
            zoomDomain={{ x: xDomain, y: yDomain }}
            minimumZoom={minimumZoom}
                clipContainerComponent={
                    <VictoryClipContainer
                        clipPadding={{ top: 10, right: 10, bottom: 10, left: 10 }}
                    />
                }
                onTouchStart={(evt) => {
                    this.locationX = evt.nativeEvent.locationX;
                }}
        />
    }
>
    <AxisWrapper tickValues={this._tickValues}>
        <VictoryAxis
            axisComponent={<LineSegment lineComponent={<NoopComponent />} />}
            ickFormat={this.xTickFormat}
            style={{
                grid: {
                    stroke: 'gray',
                    strokeDasharray: '5 5',
                },
            }}
        />
    </AxisWrapper>
    <VictoryAxis
        dependentAxis
        axisComponent={<LineSegment lineComponent={<NoopComponent />} />}
        style={{
                grid: {
                stroke: 'gray',
                strokeDasharray: '5 5',
                },
        }}
    />
    <LinearGradient />
    <VictoryArea
        data={this._data}
        interpolation="monotoneX"
        style={{
            data: {
                stroke: lineColor,
                strokeWidth: lineStroke,
                fill: LinearGradient.fill,
            },
        }}
    />
    <VictoryScatter
        data={this._data}
        style={{ data: { stroke: lineColor, fill: lineColor } }}
    />
    <Lollipop getParent={() => this} />
</VictoryChart>

尝试了一番,在iphone6下还是卡顿,所以我之前手撸的纯js控件是真的尽力了。感觉是这个js回调机制还是耗能,对低端设备有高要求的同学还是手撸一个定制化原生控件,封装给RN层傻瓜式调用吧

对于victoryNative这个库的槽点就是文档偏少,官方给的案例都带点 案例仅供参考的感觉,上起手来偏生硬吧。不过确实是RN端图表类的一个解决方案。

victory-native 官方入口
victory-native github入口
https://github.com/little-buddy/RNZoomChartDemo 如果点击404,可粘贴该地址

以前看别人的博文,行云流水一气呵成,从来没考虑过会花多少时间,而当自己真心去总结的时候发现,篇幅再短可能都不止1个小时。

愿明天是 新的一天,大步走向前。─=≡Σ(((つ•̀ω•́)つ

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 持续更新中...... 一套企业级的 UI 设计语言和 React 实现。 https://mobile.ant....
    日不落000阅读 5,540评论 0 35
  • React-Native-Elements 一组开发RN的UI工具包(强烈推荐) 🔥🔥🔥🔥🔥 react-nati...
    以德扶人阅读 45,795评论 2 135
  • 知乎上有一个热门话题:有什么事情,会让你到临终前后悔不已? 置顶回答的题目是《人死之前最后悔的五件事情》。 1.我...
    牧天狼阅读 629评论 0 0
  • 最近又迷上牡丹,国画、工笔、彩铅、线稿,只要一有空就琢磨,着迷得一塌糊涂啊!哈哈哈!所谓牡丹花下死,做鬼也风流,虽...
    萍手绘阅读 1,222评论 4 12
  • 感恩老婆对我的理解、包容与爱,让我感受家的温馨与温暖,感恩光宝宝的快乐成长,让我感受到纯真与爱,感恩死党们的聚会,...
    日精进_a07d阅读 121评论 0 5