本文介绍使用ec-canvas实现小程序图表功能,支持切换更新数据并在IOS顺畅使用。
Tips:本文只介绍柱形图,其它图形类似,具体可查看GitHub上的ecomfe/echarts-for-weixin项目。
1、文件index.wxml和index.wxss代码如下,这一块比较简单,可自行查看,不做过多分析;
<view class="container">
<view class="item-head">
<view class="tit">月份统计</view>
<picker mode="selector" bindchange="chooseChange" value="{{chooseIndex}}" range="{{choossArr}}" range-key="value" name="chooseType" class="picker-box">
<view class="picker">
{{choossArr[chooseIndex].value}}
</view>
<image src="../../images/arrow.png"></image>
</picker>
</view>
<view class="echart-heig">
<image src="{{echartImgSrc}}" class="echart-img" wx:if="{{echartImgSrc1 != ''}}"></image>
<ec-canvas id="mychart" canvas-id="mychart-bar" ec="{{ ec }}" class="{{echartImgSrc != '' ? 'hide' : ''}}"></ec-canvas>
</view>
</view>
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.item-head {
display: flex;
padding: 40rpx 30rpx 20rpx;
}
.item-head .tit {
font-size: 30rpx;
margin: 6rpx 14rpx 0 0;
}
.item-head .picker-box {
display: flex;
width: 196rpx;
height: 50rpx;
font-size: 26rpx;
line-height: 50rpx;
border-radius: 6rpx;
border: 2rpx solid #e6e6e6;
}
.item-head .picker-box .picker {
display: inline-block;
flex: 0.7;
width: 140rpx;
text-align: left;
margin-left: 20rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.item-head .picker-box image {
flex: 0.3;
width: 12rpx;
height: 8rpx;
margin-top: -34rpx;
vertical-align: middle;
}
.item-head .picker-box.ios image {
margin-top: -10rpx;
}
.hide {
display: none !important;
}
.echart-img {
width: 100%;
height: 100%;
}
.echart-heig {
width: 100%;
height: 1020rpx;
}
2、文件index.js存放所有功能的逻辑代码,代码实现如下:
1)函数chooseChange用于获取切换数据后的月份;
2)函数getFinishCount用来根据月份判断使用的数据;为了方便使用简单的数据切换,项目情况下,一般都是调用接口获取数据;有个特别要注意的,就是把echartImgSrc的值清空,不然没办法更新数据;
3)函数initEcharts是示例的核心,数据结构可自行查看官网,更新数据使用了chart.setOption(option);但这里有个比较特别的代码,就是先使用canvasToTempFilePath把指定区域生成图片,然后赋值echartImgSrc来重新渲染页面,因为直接用ec-canvas渲染,在IOS滑动会很卡。
import * as echarts from '../../ec-canvas/echarts';
const App = getApp();
Page({
data: {
villageArr: [],
villageArr1: [{
value1: 90,
value2: 78,
name: 'aaa'
},
{
value1: 145,
value2: 120,
name: 'bbb'
},
{
value1: 98,
value2: 87,
name: 'ccc'
},
{
value1: 126,
value2: 102,
name: 'ddd'
},
{
value1: 90,
value2: 90,
name: 'eee'
},
{
value1: 108,
value2: 100,
name: 'fff'
},
{
value1: 134,
value2: 120,
name: 'ggg'
}
],
villageArr2: [{
value1: 50,
value2: 45,
name: 'aaa'
},
{
value1: 40,
value2: 36,
name: 'bbb'
},
{
value1: 70,
value2: 67,
name: 'ccc'
},
{
value1: 80,
value2: 54,
name: 'ddd'
},
{
value1: 77,
value2: 55,
name: 'eee'
},
{
value1: 66,
value2: 57,
name: 'fff'
},
{
value1: 80,
value2: 50,
name: 'ggg'
}
],
ec: {},
echartImgSrc: '', // canvas在ios下滑动问题,目前只能将echarts图表渲染完成后再生成为图片展示。
chooseIndex: 0, // 选中的下标
choossArr: [{
value: '1月',
id: 1
},
{
value: '2月',
id: 2
}
]
},
// 切换不同数据
getFinishCount: function (month) {
let self = this;
if (month === 1) {
this.setData({
villageArr: this.data.villageArr1,
echartImgSrc: ''
});
} else {
this.setData({
villageArr: this.data.villageArr2,
echartImgSrc: ''
});
}
self.initEcharts();
},
// 数据渲染
initEcharts: function (canvas, width, height) {
let that = this;
this.selectComponent('#mychart').init((canvas, width, height) => {
// 初始化图表
const chart = echarts.init(canvas, null, {
width: width,
height: height
});
let villageArr = that.data.villageArr;
let villageArrName = [];
let villageArrValue1 = [];
let villageArrValue2 = [];
villageArr.map(function (item, index) {
villageArrName.push({
value: item.name,
id: index
});
villageArrValue1.push({
value: item.value1
});
villageArrValue2.push({
value: item.value2
});
})
this.setData({
villageArr: villageArr
})
let option = {
color: ["#58a7f8", "#63e669"],
legend: {
data: ['上报量', '完成量'],
top: 0,
left: 10,
icon: 'roundRect',
itemWidth: 13,
itemHeight: 13,
itemGap: 20,
},
grid: {
left: 15,
right: 25,
bottom: 0,
top: 35,
containLabel: true
},
xAxis: {
type: 'value',
axisTick: {
show: false
},
axisLine: {
show: false,
},
splitLine: {
lineStyle: {
color: '#e6e6e6'
}
},
axisLabel: {
textStyle: {
color: '#6a737d'
}
}
},
yAxis: {
type: 'category',
axisTick: {
show: false
},
axisLine: {
show: false,
},
axisLabel: {
textStyle: {
color: '#6a737d',
fontSize: 11,
align: 'right',
},
formatter: function (value, index) {
if (value.length > 6) return value.slice(0, 6) + '...';
else return value;
}
},
data: villageArrName
},
series: [{
name: '上报量',
type: 'bar',
barWidth: 12,
barGap: '-100%',
data: villageArrValue1
},
{
name: '完成量',
type: 'bar',
barWidth: 12,
data: villageArrValue2
}
]
};
chart.on('finished', () => {
that.selectComponent('#mychart').canvasToTempFilePath({
success: res => {
that.setData({
echartImgSrc: res.tempFilePath
})
wx.hideLoading();
},
fail: res => console.log('转换图片失败', res)
});
})
chart.setOption(option);
return chart;
});
},
// 选项改变触发
chooseChange: function (e) {
wx.showLoading({
title: '加载中',
mask: true
});
this.setData({
chooseIndex: e.detail.value
})
let month = this.data.choossArr[e.detail.value].id;
this.getFinishCount(month);
},
// 加载页面
onLoad: function () {
wx.showLoading({
title: '加载中',
mask: true
});
// 默认第一月数据
this.getFinishCount(1);
}
});