小程序使用echarts 在一个页面打印多个饼图的坑

一、下载echarts微信版

下载地址:https://github.com/ecomfe/echarts-for-weixin
或者直接云盘下载 https://pan.baidu.com/s/1iOXILEZlmGYzzSin_TK22A 提取码 fwhx

二、创建所需文件

同时将下载的echarts 文件拷入,目录如下
在这里插入图片描述

三、创建一个配置option 的js

echart-option-config.js 配置option相关数据

var getOption = function (title,seriesName, dataArray) {
  var option = {
    title: {
      text: title ||'数据来源',
      x: 'left',
      textStyle:{
        fontSize:36
      }
    },
    tooltip: {
      trigger: 'item',
      formatter: "{a} <br/>{b}: {c} ({d}%)"
    },
    series: [
      {
        name: seriesName || '访问来源',
        type: 'pie',
        radius: ['30%', '55%'],
        labelLine: { // 设置指示线的长度
          normal: {
            length: 8,
            length2: 8
          }
        },
        label: {
          normal: {
            formatter: '{b|{b}:}\n{c}\n{per|{d}%}  ',
            rich: {
              b: {
                fontSize: 12,
                lineHeight: 20,
                align: 'center' // 设置文字居中
              },
              per: {
                color: '#eee',
                backgroundColor: '#334455',
                padding: [2, 4],
                borderRadius: 2,
                align: 'center',
              }
            }
          }
        },
        data: dataArray || [
          { value: 135, name: '视频广告' },
          { value: 148, name: '百度' },
          { value: 251, name: '谷歌' },
        ]
      }
    ]
  };
  return option;
}
module.exports = getOption;

四、页面布局和具体实现

1、report-detail.wxml 布局页面

<view>
  <view class="detail-head">
    <text>{{caption}}月报</text>
  </view>
  <text class="caption-sub">数据来源</text>
  <view class="desc">
    <text>截止</text>
    <text>{{caption}}</text>
    <text> {{contentTxt}}</text>
    <text class="data-list-num">{{spaceNum}}</text>
    <text>条,其中:</text>
    <view class="data-list">
      <view>
        <text>存量数据导入:</text>
        <text class="data-list-num">{{stockNum}}</text>
        <text>条;</text>
      </view>
      <view>
        <text>异构接入数据:</text>
        <text class="data-list-num">{{specialNum}}</text>
        <text>条;</text>
      </view>
      <view>
        <text>互联网抓取数据:</text>
        <text class="data-list-num">{{internetNum}}</text>
        <text>条;</text>
      </view>
    </view>
  </view>
  <view class="echart_panel">
    <ec-canvas id="sorce-pie" canvas-id="source-pie" ec="{{ecLine}}" bind:init="echartInit_source"></ec-canvas>
  </view>
   <view class="hr"></view>
  <view class="echart_panel">
    <ec-canvas id="type-pie" canvas-id="type-pie" ec="{{ecLineSeason}}" bind:init="echartInit_type"></ec-canvas>
  </view>
</view>

2、report-detail.js加载页面数据

import * as echarts from '../../../ec-canvas/echarts';
var getOptionByExternalJs = require('../../../echart-template/echart-option-config.js');
var optionConfig = new getOptionByExternalJs();
Page({

  /**
   * 页面的初始数据
   */
  data: {
    contentTxt: '平台通过存量数据导入,异构数据导入、异构系统/平台计入及互联网抓取方式,共汇集空间信息数据',
    spaceNum: 23423,
    stockNum: 234422,
    specialNum: 347458,
    internetNum: 89079,
    ecLine: {},
    ecLineSeason: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    // 接收上一个页面传入的年、季、月
    var month = options.month;
    var year = options.year;
    var season = options.season;
    // 将其挂载到data便于页面使用
    this.setData({
      caption: year + month
    });
    this.printPie(); // 打印饼图
  },
  /**
   * 打印饼图
   * 
   */
  printPie: function() {
    let that = this;
    // 初始化echarts ,同时挂载到data

    wx.showLoading({
      title: '数据加载中......',
    })
    // 此处假设我们使用wx.requiest请求后台获取到了所需数据,重置option
    //打印第一个图形 [数据来源]
    setTimeout(function() {
      that.loadEchartsByBackstage(
        that.data.initchartSource,
        '数据来源',
        '当月月报', [{
            value: 9432,
            name: '互联网抓取数据'
          },
          {
            value: 24123,
            name: '存量导入数据'
          },
          {
            value: 14242,
            name: '异构接入数据'
          }
        ]);
      //打印第二个图形【数据分类】
      that.loadEchartsByBackstage(
        that.data.initchartType,
        '数据分类',
        '当前季度', [{
            value: 19432,
            name: '春节'
          },
          {
            value: 24123,
            name: '秋季'
          },
          {
            value: 14242,
            name: '夏季'
          },
          {
            value: 24242,
            name: '冬季'
          }
        ]);
      wx.hideLoading();
    }, 200);
  },
  /**
   * 初始化echats
   * @return {Object} echart
   * 
   */
  initChart: function(canvas, width, height) {
    const chart = echarts.init(canvas, null, {
      width: width,
      height: height
    });
    canvas.setChart(chart);
    chart.setOption(optionConfig);
    return chart;
  },
  // 来源
  echartInit_source(e) {
    this.data.initchartSource = this.initChart(e.detail.canvas, e.detail.width, e.detail.height);
  },
  //分类
  echartInit_type(e) {
    this.data.initchartType = this.initChart(e.detail.canvas, e.detail.width, e.detail.height);
  },
  /**
   * 从服务器获取数据
   * 
   */
  loadEchartsByBackstage: function(echarCasch, title, seriesName, dataArray) {
    echarCasch.setOption({
      title: {
        text: title
      },
      series: [{
        name: seriesName,
        data: dataArray
      }]
    });
  }
})

3、report-detail.json 引入echarts

{
  "navigationBarTitleText": "报告详情",
  "usingComponents": {
    "ec-canvas": "../../../ec-canvas/ec-canvas"
  }
}

4、report-detail.wxss 设置页面样式

.detail-head {
  margin-left: 12px;
  font-weight: 700;
}

.caption-sub {
  margin-left: 12px;
  font-size: 12px;
  font-weight: bold;
}

.desc {
  margin: 12px;
  font-size: 14px;
  line-height: 28px;
}
.data-list{
  display: flex;
  flex-direction: column;
}
.data-list-num{
  color:#3cbaff;
}
.echart_panel{
  width: 100%;
  height: 600rpx;
}
.hr {
  border: 1px solid #ccc;
  opacity: 0.2;
  width: 78%;
  margin: 0 auto;
  background-color: red;
  margin-bottom: 20px;
}

五、测试真机运行异常

上面代码在电脑模拟运行完全没问题,但是使用真机测试就会报错,如下图
在这里插入图片描述

WAService.js:1 thirdScriptError
Cannot read property 'setOption' of undefined;at pages/analysis-report/report-detail/report-detail onLoad function;at setTimeout callback function
TypeError: Cannot read property 'setOption' of undefined
    at ge.loadEchartsByBackstage (weapp:///pages/analysis-report/report-detail/report-detail.js:110:16)
    at Function.<anonymous> (weapp:///pages/analysis-report/report-detail/report-detail.js:54:12)
    at WAService.js:1:102995
    at Timeout._onTimeout (WAService.js:1:90534)
    at listOnTimeout (internal/timers.js:535:17)
    at processTimers (internal/timers.js:479:7)

一直纠结于为什么setOption未定义,找了好久都没明白为啥!
最后改了无数次代码,想到了可能是初始化echarts实例并未完成,就使用setTimeout模拟后台请求数据,
造成了在调用loadEchartsByBackstage时传入的that.data.initchartSource,
其实就是一个undefined(因为echartInit_source函数尚未初始完,
理所当然此时将ecahrts挂载到data中的操作也还没有执行)所以会有如上错误



最后我将setTimeout延时加长问题就没有了

/**
   * 打印饼图
   * 
   */
  printPie: function () {
    let that = this;
    // 初始化echarts ,同时挂载到data

    wx.showLoading({
      title: '数据加载中......',
    })
    // 此处假设我们使用wx.requiest请求后台获取到了所需数据,重置option
    //打印第一个图形 [数据来源]
    setTimeout(function () {
      ...
    }, 2000);

但是这个肯定不是最终的处理办法(假如应用出现初始化卡顿,延时是否就不够了呢)!



最后想到了使用promise 来先获得echarts 实例

  /**
 * 初始化echats
 * 使用promise获取初始化echarts 实例
 * @return {Object} echart
 * 
 */
  initChart: function (canvas, width, height) {
    return new Promise(resolve => {
      const chart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      canvas.setChart(chart);
      chart.setOption(optionConfig);
      resolve(chart);
    });
  },

再将onload中的printPie()函数移到echarts的初始化中,再在data挂载变量标识printPie()是否已经被调用,如果未调用就调用该函数模拟获取数据重新渲染option;这样就OK了。

 // 来源
  echartInit_source(e) {
     this.initChart(e.detail.canvas, e.detail.width, e.detail.height).then(res => {
       this.data.initchartSource = res;
       // 判断所以echarts 实例都初始完毕;并且invokePrintPie为false
       if (this.data.initchartType && this.data.initchartSource && !this.data.invokePrintPie){
         this.printPie(); // 打印饼图
         this.data.invokePrintPie = true;
       }
       return res;
    });
  },

修改后的report-detail.js完整代码

import * as echarts from '../../../ec-canvas/echarts';
var getOptionByExternalJs = require('../../../echart-template/echart-option-config.js');
var optionConfig = new getOptionByExternalJs();
Page({

  /**
   * 页面的初始数据
   */
  data: {
    contentTxt: '平台通过存量数据导入,异构数据导入、异构系统/平台计入及互联网抓取方式,共汇集空间信息数据',
    spaceNum: 23423,
    stockNum: 234422,
    specialNum: 347458,
    internetNum: 89079,
    invokePrintPie:false,//标识是否已经调用打印饼图操作
    ecLine: {},
    ecLineSeason: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 接收上一个页面传入的年、季、月
    var month = options.month;
    var year = options.year;
    var season = options.season;
    // 将其挂载到data便于页面使用
    this.setData({
      caption: year + month
    });
    //this.printPie(); // 打印饼图
  },
  /**
   * 打印饼图
   * 
   */
  printPie: function () {
    let that = this;
    // 初始化echarts ,同时挂载到data

    wx.showLoading({
      title: '数据加载中......',
    })
    // 此处假设我们使用wx.requiest请求后台获取到了所需数据,重置option
    //打印第一个图形 [数据来源]
    setTimeout(function () {
      that.loadEchartsByBackstage(
        that.data.initchartSource,
        '数据来源',
        '当月月报', [{
          value: 9432,
          name: '互联网抓取数据'
        },
        {
          value: 24123,
          name: '存量导入数据'
        },
        {
          value: 14242,
          name: '异构接入数据'
        }
        ]);
      //打印第二个图形【数据分类】
      that.loadEchartsByBackstage(
        that.data.initchartType,
        '数据分类',
        '当前季度', [{
          value: 19432,
          name: '春节'
        },
        {
          value: 24123,
          name: '秋季'
        },
        {
          value: 14242,
          name: '夏季'
        },
        {
          value: 24242,
          name: '冬季'
        }
        ]);
      wx.hideLoading();
    }, 200);
  },
  /**
 * 初始化echats
 * 使用promise获取初始化echarts 实例
 * @return {Object} echart
 * 
 */
  initChart: function (canvas, width, height) {
    return new Promise(resolve => {
      const chart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      canvas.setChart(chart);
      chart.setOption(optionConfig);
      resolve(chart);
    });
  },
  // 来源
  echartInit_source(e) {
     this.initChart(e.detail.canvas, e.detail.width, e.detail.height).then(res => {
       this.data.initchartSource = res;
       // 判断所以echarts 实例都初始完毕;并且invokePrintPie为false
       if (this.data.initchartType && this.data.initchartSource && !this.data.invokePrintPie){
         this.printPie(); // 打印饼图
         this.data.invokePrintPie = true;
       }
       return res;
    });
  },
  //分类
  echartInit_type(e) {
    this.initChart(e.detail.canvas, e.detail.width, e.detail.height).then(res => {
      this.data.initchartType = res;
      // 判断所以echarts 实例都初始完毕;并且invokePrintPie为false
      if (this.data.initchartType && this.data.initchartSource && !this.data.invokePrintPie) {
        this.printPie(); // 打印饼图
        this.data.invokePrintPie = true;
      }
      return res;
    });
   
  },
  /**
   * 从服务器获取数据
   * 
   */
  loadEchartsByBackstage: function (echarCasch, title, seriesName, dataArray) {
    echarCasch && echarCasch.setOption({
      title: {
        text: title
      },
      series: [{
        name: seriesName,
        data: dataArray
      }]
    });
  }
})

六、修改后真机预览

预览如下图 :

加载之前使用默认数据
模拟加载真实数据后

七、 字体大小无法控制

不知道大家又没注意到,echarts 的title 有些小呢?然而echarts 的optin中title 设置的字体大小是36了呢。

运行时截图
option字体设置如图

最终的解决办法是去官网定制了一个新的library;
也可以在云盘直接下载:云盘地址 https://pan.baidu.com/s/1kSsYfI0M36KVc1JdeEjvBA 提取码 lrpg
,如图:

定制柱状、折线、饼图图表
定制所需组件
下载定制的library
编译完成自动下载

最后将下载的echarts-mini.js改名为echarts.js 替换ec-canvas目录下载的echarts.js即可
在这里插入图片描述

posted @ 2019-09-20 16:46  奔跑的痕迹  阅读(1623)  评论(0编辑  收藏  举报