Uniapp小程序集成ECharts的K线图并实现动态无感加载
2025-06-24 12:24:34
来源:新华网
背景介绍
最近写了一个小程序项目,需要实现K线图的日线小时线功能,并且要支持无感加载,也就是在左右滑动k线图时,不出现停顿加载,可以无限一直滑下去,用户感知不到数据的加载。
经过我的一番摸索,最后把需求给实现了。所以打算给大家做个分享,聊一聊实现该功能我踩的一些坑,以及一些解决问题的思路。
这里补充一下,uniapp实现K线图的方式不只是要用ECharts,但是我的需求除了要实现普通的K线图以外,还有实现K线的标注,也就是在K线的某个柱子上,标记特定是数据。经过调研我发现只有ECharts的MarkPoint属性能实现我的需求,所以最终的选择了ECharts。
然后,本项目的demo源码,有需要的也会免费分享给大家,通过关注公众号【码农炼金术】,私信“k线图”获取。
项目集成
一、uniapp集成ECharts。
这个建议去官网查看集成的教程,一般都能找到。比如本案例我们可以先去uniapp官网找集成ECharts的方式,找不到我们再去ECharts官网找集成到uniapp的集成方式。
但是不排除一些比较冷门的技术,官网找不到集成的教程,这样我们再去各大网站搜索技术博文。
最终我找到是的uniapp官网的插件市场找到了集成的组件。当然有很多不同的插件,我这里综合考虑选了这款。
插件地址:https://ext.dcloud.net.cn/plugin?id=1538
二、集成方法(插件主页有介绍)。
1、下载插件
下载地址https://ext.dcloud.net.cn/plugin?id=1538
2、复制uni-ec-canvas文件夹到项目组件目录
3、项目中使用
view
js
style
// 这里一定要注意 设置该组件宽高 以及display:block来确保canvas初始化的时候是有宽高的
集成方式非常简单,接下来就可以根据自己的页面,去配置echarts的属性,配置方式直接参考eharts官方问答即可。
三、本案例集成代码
这里我就按照我的需求,给大家演示一遍。
1、按照插件提示,先指定组件容器尺寸。
2、因为使用图表过程中需要用到echarts实例,所以把echarts引入
import * as echarts from '@/components/uni-ec-canvas/echarts'
3、配置ECharts
这里参考官网的配置项
地址:https://echarts.apache.org/examples/zh/index.html#chart-type-candlestickhttps://echarts.apache.org/examples/zh/index.html#chart-type-candlestick
在线调试配置项
地址:https://echarts.apache.org/examples/zh/editor.html?c=candlestick-sh
k线图数据配置,主要是由一个多根柱子数据组成,一根柱子由主要的四个数据组成,分别是开盘价、收盘价、最高价(上引线)、最低价(下引线)。
4、完整配置项
{ lazyLoad: true, option: { animation: false, tooltip: { trigger: 'axis', showDelay: 0, hideDelay: 0, axisPointer: { type: 'cross' }, backgroundColor: '#FFF', textStyle: { color: '#616161' }, formatter: (params) => { const str = `${ params[0].name}\n开:${ params[0].data[1]}\n收:${ params[0].data[2]}\n高:${ params[0].data[4]}\n低:${ params[0].data[3]}` return str }, }, grid: { left: '10%', right: '5%', bottom: '5%' }, xAxis: { type: 'category', data: [], boundaryGap: false, axisLine: { onZero: false, show: false }, axisTick: { lineStyle: { type: 'dashed' } }, splitLine: { show: false }, min: 'dataMin', max: 'dataMax', }, yAxis: { scale: true, splitArea: { show: false}, axisLine: { show: false}, splitLine: { lineStyle: { type: 'dashed' } } }, series: [{ id: 'candlestick', name: '日K', type: 'candlestick', data: [], itemStyle: { color: '#DF1525', color0: '#0BB329', borderColor: '#DF1525', borderColor0: '#0BB329' } }], dataZoom: [{ id: 'candlestickZoom', type: 'inside', minValueSpan: 23, maxValueSpan: 23, startValue: 0, endValue: 0, zoomLock: true }] }}
配置完的效果
5、这里要重点提一下k线图中dataZoom配置的几个属性:
dataZoom-inside. startValue
数据窗口范围的起始数值。如果设置了 dataZoom-inside.start 则 startValue 失效。
dataZoom-inside.startValue 和 dataZoom-inside.endValue 共同用 绝对数值 的形式定义了数据窗口范围。
注意,如果轴的类型为 category,则 startValue 既可以设置为 axis.data 数组的 index,也可以设置为数组值本身。但是如果设置为数组值本身,会在内部自动转化为数组的 index。
关于坐标轴范围(axis extent)和 dataZoom-inside.startValue 的关系的更多信息,请参见:dataZoom-inside.rangeMode。
dataZoom-inside. endValue
数据窗口范围的结束数值。如果设置了 dataZoom-inside.end 则 endValue 失效。
dataZoom-inside.startValue 和 dataZoom-inside.endValue 共同用 绝对数值 的形式定义了数据窗口范围。
注意,如果轴的类型为 category,则 endValue 即可以设置为 axis.data 数组的 index,也可以设置为数组值本身。但是如果设置为数组值本身,会在内部自动转化为数组的 index。
关于坐标轴范围(axis extent)和 dataZoom-inside.endValue 的关系的更多信息,请参见:dataZoom-inside.rangeMode。
dataZoom-inside. minValueSpan
用于限制窗口大小的最小值(实际数值)。
如在时间轴上可以设置为:3600 * 24 * 1000 * 5 表示 5 天。在类目轴上可以设置为 5 表示 5 个类目。
dataZoom-inside. maxValueSpan
用于限制窗口大小的最大值(实际数值)。
如在时间轴上可以设置为:3600 * 24 * 1000 * 5 表示 5 天。在类目轴上可以设置为 5 表示 5 个类目。
dataZoom-inside. zoomLock
是否锁定选择区域(或叫做数据窗口)的大小。
如果设置为 true 则锁定选择区域的大小,也就是说,只能平移,不能缩放。
配置项我们这里选的是startValue和endValue模式,为什么不选start和end,这个后面我们会解释。
我们的案例将startValue和endValue初始值都设置为0,是因为我们在配置的时候,startValue和endValue是不确定的,要根据接口第一次返回的数值进行计算。比如我们接口一次返回的数据是4天的k线图,也就是4x24根柱子的数据,那么我们画布视图首屏的窗口,展示的数值范围应该是startValue=72,endValue=95,值从0开始计算。这个计算过程会在我们初始化echarts的时候去执行。
minValueSpan、maxValueSpan以及zoomLock,都是为了固定画布窗口仅展示一天的数据,也就是24根柱子。所以我们minValueSpan=23,maxValueSpan=23,zoomLock=true。
k线图配置项基本已经调试好。接下来是咱们的要说的重点,无感加载。
无感加载
先说一下思路,echarts配置接收的是一个数组,也就是多根k线柱子的数据。因为第一次加载数据,默认我们是加载当前最新的,这样我们只要考虑画布往左滑动,加载历史的k线数据即可。正常解法是,我们只要在滑动画布的时候,动态往数组里面添加数据就可以,这是我们最直观的思路。
但是实现起来并不是这么简单。
第一个面临的问题是,我们要知道是在什么地方触发加载。要实现无感加载,那么我们就不能等到画布滑动到边缘的时候再触发加载数据,这样会造成滑动停顿中断,对用户体验不好。
所以我们要在用户滑动到边缘前,提前加载下一页的数据。echarts中配置我们通过监听datazoom的变化去判断什么时候触发下一页数据加载。代码如下
chart.on('datazoom', async (event) => { this.calcStartEndValue() // 画布滑动,重新计算startValue和endValue位置 if(this.startValue <= 24){ // 当startValue 小于等于24,触发数据加载,也就是一个画布窗口的宽度 this.loadChartDatas(true) // 加载下一页数据 }});
我们通过startValue的变化来判断提前多少来加载下一页数据,这里我们设置的是startValue值变化到小于等于24时进行下一页数据加载,也就是滑动到还有一个画布窗口大小的位置时,进行触发加载下一页。
通过上面的监听配置代码,我们看到有一个calcStartEndValue的方法,是因为画布滑动的时候,我们配置的值startValue和endValue并不会自动变化,监听函数只返回了start和end的值,这两个配置是指当前画布窗口,所在整个k线图位置的百分比,所以,每次滑动画布之后,我们要手动计算当前百分比做在的startValue和endValue值是多少,这样才能保正我们在动态加载下一页数据时,计算出准确的startValue和endValue位置的值,保证加载数据时,画布不会跳转到错误的窗口位置。
所以,到这里大家应该已经能知道我们为什么不直接使用start和end的值作为配置项。是因为这两个配置项是百分比,当我们动态加载数据时,总数据量变多了,我们百分比不变的情况下,表示是数据范围就变大了,这样会导致我们minValueSpan和maxValueSpan值失效,画布视图窗口数据总览也会变多导致滑动交互出现错误。
可能有小伙伴想说,通过动态计算start和end的百分比,是不是也可以实现。这个我起初尝试过,发现每次重新复制start和end时,画布定位并不准确,k线数据会出现跳动,这个应该是echarts的问题,大家可以去尝试一下。
综上所述,所以我们最终是使用startValue和endValue配置,数据加载时通过重新计算startValue和endValue再赋值,可以保持画布位置不固定不乱跳动。
calcStartEndValue计算方法
calcStartEndValue(first){ if(first){ this.startValue = this.chartDatas.categoryData.length - 24; this.endValue = this.chartDatas.categoryData.length - 1; }else { let start = chart.getOption().dataZoom[0].start; this.startValue = parseInt(start / 100 * this.chartDatas.categoryData.length); this.endValue = this.startValue + 23; }}
loadChartDatas方法
async loadChartDatas(add){ console.log('加载数据...'); const chartDatas = await Api.getChartDatas(); if(add){ this.startValue = this.startValue + chartDatas.categoryData.length; this.endValue = this.startValue + 23; this.chartDatas.categoryData = [...chartDatas.categoryData, ...this.chartDatas.categoryData]; this.chartDatas.values = [...chartDatas.values, ...this.chartDatas.values]; // console.log('new_start', this.startValue); chart.setOption({ xAxis: { data: this.chartDatas.categoryData, }, series: [{ id: 'candlestick', data: this.chartDatas.values }], dataZoom: [{ id: 'candlestickZoom', startValue: this.startValue, endValue: this.endValue }], }); }else { this.chartDatas = chartDatas; this.calcStartEndValue(true); }}
最后补充一点,uni-ec-canvas中的echarts.js包,是可以从echarts官网自定义构建来替换的,按需构建可以减少包的文件大小。
但是需要注意echarts的版本不要超过v4.9.0。因为uni-ec-canvas最新的版本是1.0.3,在2020-08-17更新的。也就意味着,echarts的版本不要超过2020-08-17这个时间点,对应的这个时间之前最新的版本就是v4.9.0。
(uni-ec-canvas插件)
(echarts官网)
源码分享
关注【码农炼金术】公众号后,发送"k线图"获取完整案例源码。