在微信小程序中引入 ECharts 图表

前言

最近在忙着做光电竞赛的项目。为了实现手机端对数据的访问,我重新拾起年初做的那一个微信小程序,在该小程序的基础上添加了部分新功能。我们最初设想的功能是物联网开发,利用传感器采集温度数据并上传至服务器,再通过小程序读取数据库中的数据,绘制温度变化曲线。前面数据采集这一部分交给了同学去做,我负责的是小程序这一部分内容。

我构思的小程序功能是,第一个页面展示近一周的温度变化曲线,再添加一个按钮,跳转到另一个页面展示全部数据。由于目前硬件设备尚未开发,所以我利用原先的小程序当中的「家庭记账本」中的添加「添加收支」页面,对其进行改写,做了个添加新数据的功能,能够任意添加或删除数据。目前数据库采用的是小程序云开发默认的数据库。

ECharts 是一个纯 Javascript 的图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。为了在小程序中实现数据可视化,ECharts 是一个不错的选择。幸运的是,目前有一个微信小程序版 ECharts 库可以直接使用:

ECharts 的微信小程序版本
JavaScript

根据静态数据绘制图像

首先将该仓库下载下来,将仓库中的 ec-canvas 文件夹存放在和 app.js 同级的目录下。我要将 ECarts 插入到 temperature-list 页面中,所以在 temperature-list.json 中引入该组件:

1
2
3
4
5
{
  "usingComponents": {
    "ec-canvas": "../../ec-canvas/ec-canvas"
  }
}

我想要实现的是绘制温度变化曲线,在仓库所给的示例程序中,有一个名为在 line 的例程,这一例程正好达到了我的要求,所以可以参考该例程进行编写。在 temperature-list.wxml 中添加 ECharts 图表。

insert-echart-into-wechat-mini-app-0.png

1
2
3
<view class="container">
  <ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>
</view>

然后在 temperature-list.wxss 中添加下面的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* pages/temperature-list/temperature-list.wxss */

page {
  background-color: #f7f7f7;
}
ec-canvas {
  width: 100%;
  height: 100%;
}
ec-canvas {
  width: 100%;
  height: 100%;
}
.container {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
}
.picker-pos {
  margin-top: -130rpx;
  margin-left: 150rpx;
  color: blueviolet;
}

最后在 temperature-list.js 中添加:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// pages/temperature-list/temperature-list.js

var echarts = require("../../ec-canvas/echarts.js");

const app = getApp();

function initChart(canvas, width, height, dpr) {
  const chart = echarts.init(canvas, null, {
    width: width,
    height: height,
    devicePixelRatio: dpr // new
  });
  canvas.setChart(chart);

  var option = {
    title: {
      text: '近七日温度统计',
      left: 'center'
    },
    color: ["#37A2DA"],
    grid: {
      containLabel: true
    },
    tooltip: {
      show: true,
      trigger: 'axis'
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: ['2020-07-05', '2020-07-06', '2020-07-07', '2020-07-08', '2020-07-09', '2020-07-10', '2020-07-11'],
      // show: false
    },
    yAxis: {
      x: 'center',
      min: 36,
      max: 37,
      type: 'value',
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
      // show: false
    },
    series: [{
      name: 'GuanQirui',
      type: 'line',
      smooth: true,
      data: [36.6, 36.2, 36.5, 36.5, 36.5, 36.5, 36.5]
    }]
  };

  chart.setOption(option);
  return chart;
}

Page({
  data: {
    ec: {
      onInit: initChart
    }
  }
})

编译后即可看到绘制的曲线图。

insert-echart-into-wechat-mini-app-1.png◎ 绘制的曲线

不过目前我使用的数据是静态的,直接存储在代码中,并不能够修改,也就无法根据实时数据绘制曲线。为了实现该功能,和「家庭记账本」一样,我使用到了小程序的云开发。这里我创建了一个名为 temp 的集合,存储在这里的每一条记录,都需要包含姓名、温度、位置、日期这四个元素。

将数据上传至数据库

我在显示温度变化曲线的页面添加一个按钮,点击能够跳转查看全部统计信息,点击右下角的加号按钮就能够添加新的数据到数据库中。这一部分功能的实现可以参考我之前的那一篇文章——《微信小程序课程后记》,和「家庭记账本」的功能类似,这里不再赘述。

insert-echart-into-wechat-mini-app-2.png◎ 全部统计信息

insert-echart-into-wechat-mini-app-3.png◎ 添加新数据

我们利用添加新数据的功能向数据库添加了几组新的数据。

insert-echart-into-wechat-mini-app-4.png◎ 数据库页面

根据动态数据绘制图像

接下来就是最为关键的部分——如何载入这些数据并绘制曲线。

观察绘图的函数可知,绘图需要的变量只有三个——姓名、温度、日期。因此可以创建三个数组(nametemperaturedate)存放这三组数据。然后在 option 中将原来的数组替换为现在的数组。

从数据库获取数据很简单,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const db = wx.cloud.database();
db.collection('temp').get({
  success: res => {
    name = [];
    date = [];
    temperature = [];
    res.data.reverse();
    name.push(res.data[0].name);
    for(var i=6; i>=0; i--) {
      date.push(res.data[i].date);
      temperature.push(res.data[i].temperature);
    }
  }
});

如果你直接按照这种方法,对上面的程序进行改写,编译后可以发现图像并没有出来,是一个只有坐标轴的空白图像。虽然我们获取到了数据库中的数据,但是图像并没有更新。所以我们需要设置图像为懒加载(lazyLoad: true),并在页面加载的时候载入数据,再绘制图像。完整的代码如下所示:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// pages/temperature-list/temperature-list.js

var echarts = require("../../ec-canvas/echarts.js");

var name = [];
var date = [];
var temperature = [];
var Chart = null;

Page({
  data: {
    ec: {
      lazyLoad: true
    },
    temp: [],
  },

  seeDetail: function () {
    setTimeout(function () {
        wx.navigateTo({
          url: '/pages/temperature-list-detail/temperature-list-detail',
      })
    }, 50)
  },

  onLoad: function (options) {
    this.echartsComponnet = this.selectComponent('#mychart-dom-line');
    this.getData(); // 获取数据
  },

  getData: function () {
    // 如果是第一次绘制
    if (!Chart){
      this.init_echarts(); // 初始化图表
    }else{
      this.setOption(Chart); // 更新数据
    }

    // 从数据库获取数据
    const db = wx.cloud.database();
    db.collection('temp').get({
      success: res => {
        name = [];
        date = [];
        temperature = [];
        res.data.reverse();
        name.push(res.data[0].name);
        if (res.data.length < 7) {
          for(var i=res.data.length-1; i>=0; i--) {
            date.push(res.data[i].date);
            temperature.push(res.data[i].temperature);
          }
        } else {
          for(var i=6; i>=0; i--) {
            date.push(res.data[i].date);
            temperature.push(res.data[i].temperature);
          }
        }
        this.init_echarts();
      }
    });
  },

  // 初始化图表
  init_echarts: function () {
    this.echartsComponnet.init((canvas, width, height) => {
      // 初始化图表
      Chart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      this.setOption(Chart);
      // 注意这里一定要返回 chart 实例,否则会影响事件处理等
      return Chart;
    });
  },

  setOption: function (Chart) {
    Chart.clear();  // 清除
    Chart.setOption(this.getOption());  //获取新数据
  },

  getOption: function () {
    // 指定图表的配置项和数据
    var option = {
      title: {
        text: '近七日温度统计(℃)',
        left: 'center'
      },
      color: ["#37A2DA"],
      grid: {
        containLabel: true
      },
      tooltip: {
        show: true,
        trigger: 'axis'
      },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: date,
      },
      yAxis: {
        x: 'center',
        min: 36,
        max: 37,
        type: 'value',
        splitLine: {
          lineStyle: {
            type: 'dashed'
          }
        }
      },
      series: [{
        name: name,
        type: 'line',
        smooth: true,
        data: temperature,
      }]
    };
    return option;
  }
})

如果在绘制完图像后,再添加新的数据,那么当前图像页面需要刷新才能显示新的数据。因此我还添加了一个刷新(refresh)按钮:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 刷新数据
refresh: function () {
  const db = wx.cloud.database();
  db.collection('temp').get({
    success: res => {
      name = [];
      date = [];
      temperature = [];
      res.data.reverse();
      name.push(res.data[0].name);
      if (res.data.length < 7) {
        for(var i=res.data.length-1; i>=0; i--) {
          date.push(res.data[i].date);
          temperature.push(res.data[i].temperature);
        }
      } else {
        for(var i=6; i>=0; i--) {
          date.push(res.data[i].date);
          temperature.push(res.data[i].temperature);
        }
      }
      this.init_echarts();
    }
  });
}

完整的页面如下图所示。

insert-echart-into-wechat-mini-app-5.png