昨天接到一个需求是要把之前在PC中做的echarts图及功能在小程序中也实现;想着可能只是复制粘贴的事,因为是第一次在小程序中引入使用图表,结果被里面的各种坑磕磕绊绊了一整天,所以决定写下我的第一篇文章;

以下就是本菜ji半懵半懂实现该功能的过程;本篇是给像我这样的萌新朋友准备,或者是打算做类似需求的伙伴们借鉴的,如果有更好的方法或者不足之处,欢迎看过的各位前辈大佬指教。
1.进入官网下载最新的echarts包 echarts.apache.org/zh/builder.…
在这里我的需求是暂时只要饼状图,所以定制下载了饼图
2.在小程序端的话 官方也是有专门的小程序版的包,可以直接上github上下载实例
手机扫描可以体验效果:

3.引入ec-canvas组件
首先我们得把ec-canvas文件夹放进小程序项目中,然后到需要使用到图表的文件中对应index.json中挂载:
{
"usingComponents": {
"ec-canvas": "../../ec-canvas/ec-canvas"
}
}
这一配置的作用是,允许我们在 pages/bar/index.wxml 中使用 <ec-canvas> 组件。注意路径的相对位置要写对,如果目录结构和本例相同,就应该像上面这样配置。
index.wxml 中,我们创建了一个<ec-canvas>组件,内容如下:
<ec-canvas id="activeChart" ec="{{ ec_active }}"></ec-canvas>
注意:2d的ec-canvas在真机调试的时候可能会无法显示,但是上线后应该是没有问题的,如果想真机调试的话,可以在标签中加上以下代码,但这样会导致图表失真,开发完以后别忘了删除呀
force-use-old-canvas="true"
其中 ec_active 是一个我们在 index.js 中定义的对象,本次我一共需要使用到三个ec对象,它使得图表能够在页面加载后被初始化并设置。index.js 的结构如下:
import * as echarts from '../ec-canvas/echarts';
var app = getApp();
Page({
data: {
ec_active: {
// onInit: initChart
},
ActivetableData: [], // 活跃会员
activeVip: [],
},
})
申明变量后,首先请求接口获取图表信息
getActiveUserBread() {
var that = this;
app.ajax({
type: 'post',
url: 'MemberAnalyzeActive',
data: {
},
success: res => {
if (res.status == 1) {
console.log(res);
that.data.activeVip = res.data
that.setData({
activeVip: that.data.activeVip
})
this.initChart() //初始化图表
}
}
})
},
然后这个接口的我是在onLoad里调用的
onLoad: function (options) {
this.activeComponnet = this.selectComponent('#activeChart');
this.getActiveUserBread()
},
//这个selectComponent里的值必须是在wxml里对应ec-canvas的id
获取到信息后我存入了activeVip里 供后续初始化后使用
initChart: function () {
this.activeComponnet.init((canvas, width, height) => {
// 初始化图表
const Chart = echarts.init(canvas, null, {
width: width,
height: height
});
Chart.setOption(this.getOption()); //注意这里调用了getOption来返回对应的图表
return Chart;
});
},
这个initChart事件会执行到setOption的时候执行里面的this.getOption())来获取返回的option值
getOption: function () {
var option = {
backgroundColor: "#ffffff",
color: ["#37A2DA", "#32C5E9", "#67E0E3", "#91F2DE", "#FFDB5C", "#FF9F7F"],
series: [{
label: {
normal: {
fontSize: 14
}
},
type: 'pie',
center: ['50%', '50%'],
radius: '60%',
label: {
normal: {
formatter: '{b}\n({d}%)\n{c}人',
textStyle: {
fontWeight: 'normal',
fontSize: 12
}
}
},
data: this.data.activeVip,
}]
};
return option
},
一系列操作图形的显示优化后,我把option返回到调用的函数中 其实这样已经可以显示图表了,但是我这边需要点击具体的一块,获取信息并渲染到表中,然后经过一顿盘查
initChart: function () {
this.activeComponnet.init((canvas, width, height) => {
// 初始化图表
const Chart = echarts.init(canvas, null, {
width: width,
height: height
});
Chart.setOption(this.getOption());
Chart.on('click', (params) => {
this.getActiveUser(params.name)
})
return Chart;
});
其实就是在初始化图表的时候加了个事件,但是在小程序中居然可以使用click事件,这也是让我很意外的,这样就跟在PC中的操作类似了,但是其中有一点特别需要注意,这也让我今天花费了不少时间排错,就是里面的params它是这个实例的对象,我们本可以作为参数直接传进点击事件的函数中,但是它报错了,由于现在没有图,不过类似于这样

params的问题,有可能是这个对象太大了导致传递报错,所以我直接this.getActiveUser(params.name)获取了其中我需要传过去的参数,结果真是这样,以下是点击获取并存储点击后的数据
getActiveUser: function (params) {
console.log(params);
if (params != this.data.paramsList) {
this.setData({
paramsList: params,
ActiveCurrentPage: 0,
})
}
var that = this
if (that.data.canLoad) {
that.setData({
canLoad: false,
isLoad: true
})
}
var page = parseInt(that.data.ActiveCurrentPage) + 1;
var canLoad = that.data.canLoad;
wx.showLoading({
title: '加载中',
mask: true,
})
app.ajax({
type: 'post',
url: 'MemberAnalyzeActiveList',
data: {
timestamp: params,
page: page,
pageSize: 10
},
success: res => {
wx.hideLoading();
if (res.status == 1) {
var ActivetableData = that.data.ActivetableData
var canLoad = true;
if (page == 1) {
ActivetableData = res.data.list
} else {
var otherList = res.data.list;
ActivetableData.push.apply(ActivetableData, otherList);
}
if (res.data.list.length < 10) {
canLoad = false;
}
that.setData({
ActivetableData: ActivetableData,
canLoad: canLoad,
ActiveCurrentPage: page,
isLoad: false
})
} else {
that.setData({
isLoad: false
})
wx.showToast({
title: "暂无数据",
icon: 'none',
duration: 1000,
mask: true,
})
}
}
})
},哦
有好多目的之外的代码,只是为了更好的显示效果,这样大致就没问题了
但我需要用到三张表,这倒不是问题,照着如上的方法,修改一些值就可以直接生成了;接着我想把这三张表放进微信官方的swiper里面让它们能滑动展示并可以点击渲染到表格,所以我是如下做的
<view style="height:100%">
<swiper duration="500" style="height:600rpx" bindchange="swiperChange">
<swiper-item>
<view>
<view class="viphead">活跃会员</view>
<view class="circle_vip">
<view class="container">
<!-- force-use-old-canvas="true" -->
<ec-canvas id="activeChart" ec="{{ ec_active }}"></ec-canvas>
</view>
</view>
</view>
</swiper-item>
<swiper-item >
<view>
<view class="viphead">沉睡会员</view>
<view class="circle_vip">
<view class="container">
<!-- force-use-old-canvas="true" -->
<ec-canvas id="sleepChart" ec="{{ ec_sleep }}"></ec-canvas>
</view>
</view>
</view>
</swiper-item>
<swiper-item>
<view>
<view class="viphead">生日会员</view>
<view class="circle_vip">
<view class="container">
<!-- force-use-old-canvas="true" -->
<ec-canvas id="sleepChart" ec="{{ ec_sleep }}"></ec-canvas>
</view>
</view>
</view>
</swiper-item>
</swiper>
写完没毛病,也是可以展示的,但是它的点击事件就是触发不了,一开始我以为是在bindtap或者touchstart的小程序中使用onclick本身就不好,但结果发现不是这个原因,思考了挺久想想有可能跟swiper和echarts的执行顺序或者他们之间的渲染机制有关系,所以我用了一个很笨的办法
swiperChange: function (e) {
console.log(e);
this.setData({
pieIndex: e.detail.current
})
if (e.detail.current == 0) {
this.activeComponnet = this.selectComponent('#activeChart');
this.getActiveUserBread()
}
if (e.detail.current == 1) {
this.sleepComponnent = this.selectComponent('#sleepChart');
this.getSleepUserBread()
} else if (e.detail.current == 2) {
this.birthComponnent = this.selectComponent('#birthChart');
this.getBirthUserBread()
}
this.setData({
ActivetableData: []
})
},
就是根据swiper发生改变时候,在拿到它的index值后再进行初始化图表,结果这样真的解决了。
另外我还尝试了在Page({...})的外面init出饼图,图是可以正常出来,利用promise同步执行获取到值也可以渲染到图表上,但它的事件怎么也触发不了,所以我放弃了,下面附上我放弃的代码
import * as echarts from '../ec-canvas/echarts';
var app = getApp();
Page({
data: {
ec_active: {
onInit: initChart
},
ActivetableData: [], // 活跃会员
ActiveCurrentPage: 1,
pagesize: 10,
activeVip: [],
paramList: {}, //饼状图参数
},
toUserDetail: function (e) {
wx.navigateTo({
url: '../vipdetail/vipdetail'
})
},
// 活跃会员
getActiveUserBread() {
var store_id = wx.getStorageSync('storeid');
var merchant_id = wx.getStorageSync('merchantid');
var that = this;
app.ajax({
type: 'post',
url: 'MemberAnalyzeActive',
data: {
store_id: store_id,
merchant_id: merchant_id
},
success: res => {
if (res.status == 1) {
console.log(res);
that.data.activeVip = res.data
that.setData({
activeVip: that.data.activeVip
})
}
}
})
},
//生命周期函数--监听页面加载
onLoad: function (options) {
},
})
function initChart(canvas, width, height, dpr) {
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: dpr // new
});
canvas.setChart(chart);
var activeVip = []
let promise = new Promise((resolve, reject) => {
app.ajax({
type: 'post',
url: 'MemberAnalyzeActive',
data: {},
success: res => {
if (res.status == 1) {
activeVip = res.data
resolve(res.data)
} else {
reject()
}
}
})
})
promise.then(() => {
var option = {
backgroundColor: "#ffffff",
color: ["#37A2DA", "#32C5E9", "#67E0E3", "#91F2DE", "#FFDB5C", "#FF9F7F"],
series: [{
label: {
normal: {
fontSize: 14
}
},
type: 'pie',
center: ['50%', '50%'],
radius: '60%',
label: {
normal: {
formatter: '{b}\n({d}%)\n{c}人',
textStyle: {
fontWeight: 'normal',
fontSize: 12
}
}
},
data: activeVip,
}]
};
chart.setOption(option);
return chart;
})
}
哎放弃了,还是我上面的写法看着好
小结
今天是初次在小程序中使用echarts,本以为PC上可以直接复用的代码,结果遇到了好多坑,像我这样的萌新们不怎么会使用echarts小程序版的,可以随意参考一下;此外,若文中有不足的地方,欢迎留言私信呀,第一次写文章,不足之处还请前辈们见谅。
