需求分析

需要实现记录宝宝生长状况的功能,本次的成长曲线即用户记录的数据可视化,包括:身高-年龄、体重-年龄、睡眠时长-日期、睡眠规律-日期四条曲线,3张折线图 + 1张自定义(Echarts的学名)

睡眠规律视觉稿与UI大致样式

其中身高与体重的折线图需要有参考线,参考线的数据来源是产品提供的excel

参考线间的区域需要有颜色填充

初步调研

参考资料

  • echarts for weixin(附带小程序体验)
  • echarts官方文档
  • echarts官方实例
  • 医生端小程序

官方有一个自定义实例与本次实现目标很像,乍一看x/y轴倒一下即可,好像不难

初步调研后难点list:

  • 图表拖动的交互实现
  • 折线间区域的颜色填充
  • 图表UI细节涉及的配置项过多
  • 数据处理的工作量较大

技术方案选择

  • 小程序
  • H5

觉得在医生端小程序上跑的效果还不错,试着跑了几个demo,发现效果还可以,滑动交互都有现成案例,决定用小程序原生开发。

开发历程

首先是杂七杂八的顶部tab与无数据,页面跳转等乱七八糟东西弄好,最后开始画图

0.后端同学先开发,约定数据结构

  • 对图表研究的还不够彻底,我自己还没有搞清楚最后需要的是什么样的数据格式
  • 管理后台基于antd pro,使用另一套图表库,相同的呈现,数据格式可能不同

最终约定了“人可读”的数据结构,并自己处理参考线的数据。

1.把图大概样子画出来

参考echarts for weixin的实例,将引用的库copy到项目中,开发工具上正常,过不了编译,微信有包体积大小限制(目前是2MB),将echarts压缩过之后,正常编译。

上线之前,可以按需定制一个echarts的生产版本,官方的下载地址

图出来了,真机预览页面滑动的时候,内容会与图表有重叠,原因是这里的布局顶部fix,图表包含在scroll-view中,小程序的canvas文档提到这一点。

2.图表初始化

组件

  1. <ec-canvas wx:if="{{!isDisposed}}" id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>

官方的图表初始化,在init的时候就传入配置,对于异步获取的,通过lazyload选项,来初始化,医生端小程序则是自己实现了一个发布订阅。

3.数据映射到视图

配置项,坐标轴的type

这里重点说一下value轴和category轴的区别

如何理解value轴是连续数据,category是离散的类目数据这句话?

就拿数学中常见的直角坐标x轴来举例子

比如说图上蓝色的标记代表了1.5, 3.3两个点,连续数据可以理解为数学中的坐标轴,(-∞,+∞)之间的任何值都可以放在轴上

类目轴的区别在于限制了坐标轴的值,只能出现限定的几个值。

这是官方的一个折线图实例,x轴上只有['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']这七个值,一旦限制好了这些category,就一定只会出现这些category,Mon与Tue之间想要有值插进来是不可能的。

轴的选择非常关键,直接决定了配置项的数据结构。

来看身高的折线图,除了用户记录的成长曲线外还有四条参考线,参考线的数据是以月为单位,而记录的时间是天为单位。

这里的实现思路是将天转化成月,比如说15天在轴上对应的就是0.5个月,使用dayjs来处理日期的计算。

4.自定义图表

官方实例链接

官方教程

官方针对自定义有专门教程,大概就是渲染函数自己去写,数据->像素由开发者来控制,一些细节处的坐标计算不是很好理解,可以自己去量,将加减关系试出来

  1. function renderSleepLawItem(params, api) {
  2. const start = api.coord([api.value(0), api.value(1)]);
  3. const end = api.coord([api.value(0), api.value(2)]);
  4. const width = api.size([0, 1])[0] * 0.2;
  5. const rectShape = echarts.graphic.clipRectByRect({
  6. x: end[0] - (width / 2),
  7. y: end[1],
  8. width: width,
  9. height: start[1] - end[1]
  10. }, {
  11. x: params.coordSys.x,
  12. y: params.coordSys.y,
  13. width: params.coordSys.width,
  14. height: params.coordSys.height
  15. });
  16. return rectShape && {
  17. type: 'rect',
  18. shape: rectShape,
  19. style: api.style()
  20. };
  21. }

5.画图流程抽象与优化项

  • 画图流程的抽象
  • echarts单例切换配置
  • 配置缓存
  • 按需创建
  • 卸载(review时候提出来的,一开始并没有考虑到)

6.图表切换的问题

  1. 上一张图的东西还保留在图上,调用echarts实例的clear方法,再重新传入配置
  2. 带上tooltip时候,切换内部报错,采用多实例实现
  3. 多实例切换又出现新的问题,卸载不了,模板代码通过循环的方式去写就报错,需要将代码重复多次

7.关于折线间颜色填充的补充

只有当设置了stack即数据堆叠的时候才能有这种效果

经验与感想

感想

  • 分清主次,先把主体功能实现
  • 复杂case的初次开发也存在迭代的,将复杂任务拆解,细化,一步一步的去做优化与抽象
  • 沉淀到文档,代码注释要有补充