Web前端小程序

小程序如何使用ECharts制作图表

2019-05-17  本文已影响206人  defaultCoder
引言

由于可以找到的关于小程序图表制作的资源匮乏, 多为使用canvas自己动手画的教程, 这些教程虽也可以实现简单的折线图, 但确实比较单一, 难以绘制个人需要的图表, canvas学习量成本较高, 所以有了这篇文章.

这里我们通过使用ECharts来完成图表的绘制.

ECharts是百度的开源数据可视化工具, 是一个纯js的图表库, 可以简单制作出我们想要的图表. 该框架开发团队在收到很多开发者的反馈后, 也提供了对小程序版本的支持(但不是npm包).

简单介绍了一下ECharts, 那么我们开始学习如何使用它.

准备工作以及了解目录结构
  1. 我们先进入ECharts为小程序版本提供的echarts-for-weixin项目地址, 下载示例项目.
  2. 然后导入到微信web开发者工具中看看效果(不是必要步骤).
    我们先简单预览一下官方提供的示例.


    echarts-for-weixin

    大家可以看到左边的模拟器中, 提供了很多图表让我们选择, 我这里选择折线图点击进去看看.


    折线图示例
    这里我就不再预览其它图表了, 我简单介绍一下右边的目录结构,
开始使用

准备工作
接下来我使用新建的一个项目为大家演示. 新建的一个项目都是这样的目录结构.

新建的小程序项目
为了让大家看到加入图表不影响原有的开发, 我打算在原有的首页中加入图表, 所以我将在原有的Hello World和用户信息展示之间加入图表展示.
  1. 我们没有必要删除已有的文件夹, 加入这个页面并不会影响我们正常的开发, 但为了规范化开发, 既然使用了外部组件, 我们在根目录新建一个文件夹components.

  2. ec-canvas拷贝到项目中的components中(上文提到ec-canvas 就是官方提供的组件, 所以我们将组件放置到刚刚创建的组件文件夹中)
    目录结构如下:

    准备目录结构
  3. 这里我是需要折线图, 所以我进入项目echarts-for-weixinpages/line中拷贝其中的代码, 到相应的文件中

代码比较多, 粘贴看着比较乱, 其实实际上只要把对应内容粘贴上去就可以了, 为了大家出错的时候方便解决我才将代码贴出, 希望可以帮到大家.

js
我们需要将这些代码拷贝到我们要添加到的index页面中的js中, 但由于index.js中本来就存在了Page({}), 所以这部分我们只把对应的数据拷贝到里面, 也就是这样:

原有index.js代码(一些处理逻辑我就不具体粘贴上来了):

//index.js
//获取应用实例
const app = getApp()
Page({
  data: {
    motto: 'Hello World',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  //事件处理函数
  bindViewTap: function() {
    ...
  },
  onLoad: function () {
    ...
  },
  getUserInfo: function(e) {
   ...
  }
})

加入了相应代码后:

//index.js
//获取应用实例
const app = getApp()
import * as echarts from '../../components/ec-canvas/echarts.js';

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

    var option = {
        title: {
            text: '测试下面legend的红色区域不应被裁剪',
            left: 'center'
        },
        color: ["#37A2DA", "#67E0E3", "#9FE6B8"],
        legend: {
            data: ['A', 'B', 'C'],
            top: 50,
            left: 'center',
            backgroundColor: 'red',
            z: 100
        },
        grid: {
            containLabel: true
        },
        tooltip: {
            show: true,
            trigger: 'axis'
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            // show: false
        },
        yAxis: {
            x: 'center',
            type: 'value',
            splitLine: {
                lineStyle: {
                    type: 'dashed'
                }
            }
            // show: false
        },
        series: [{
            name: 'A',
            type: 'line',
            smooth: true,
            data: [18, 36, 65, 30, 78, 40, 33]
        }, {
            name: 'B',
            type: 'line',
            smooth: true,
            data: [12, 50, 51, 35, 70, 30, 20]
        }, {
            name: 'C',
            type: 'line',
            smooth: true,
            data: [10, 30, 31, 50, 40, 20, 10]
        }]
    };

    chart.setOption(option);
    return chart;
}

Page({
  onShareAppMessage: function (res) {
      return {
        title: 'ECharts 可以在微信小程序中使用啦!',
        path: '/pages/index/index',
        success: function () { },
        fail: function () { }
      }
  },
  data: {
    motto: 'Hello World',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo'),
    ec: {
      onInit: initChart
    }
  },
  //事件处理函数
  bindViewTap: function() {
    ...
  },
  onLoad: function () {
    ...
  },
  getUserInfo: function(e) {
   ...
  }
})

json
json内容比较少, 就是对组件的引入语句:
index.json代码:

{
  "usingComponents": {}
}

粘贴后还需要将组件地址修改一下, 修改成我们的组件的存放路径

{
  "usingComponents": {
      "ec-canvas": "../../components/ec-canvas/ec-canvas"
  }
}

wxml
中间嵌入图表:
修改前原index.wxml文件:

<!--index.wxml-->
<view class="container">
  <view class="userinfo">
    <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
    <block wx:else>
      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
    </block>
  </view>
  <view class="usermotto">
    <text class="user-motto">{{motto}}</text>
  </view>
</view>

修改后:

<!--index.wxml-->
<view class="container">
  <view class="userinfo">
    <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
    <block wx:else>
      <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
      <text class="userinfo-nickname">{{userInfo.nickName}}</text>
    </block>
  </view>

  <!--这里是图表组件的使用-->
  <ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>
  
  <view class="usermotto">
    <text class="user-motto">{{motto}}</text>
  </view>
</view>

wxss
修改前原index.wxss文件:

/**index.wxss**/
.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.userinfo-avatar {
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.userinfo-nickname {
  color: #aaa;
}

.usermotto {
  margin-top: 200px;
}

这里我们需要加入container的宽度限制, 修改后:

/**index.wxss**/

.container {
    width: 100vw;
    height: 100vh;
}

ec-canvas {
    width: 100%;
    height: 100%;
}

.userinfo {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.userinfo-avatar {
    width: 128rpx;
    height: 128rpx;
    margin: 20rpx;
    border-radius: 50%;
}

.userinfo-nickname {
    color: #aaa;
}

.usermotto {
    margin-top: 200px;
}

这时候该拷贝的拷贝了, 粘贴也粘贴了, 效果就出现了:


效果图

效果并没有像我预想那样子, 把图表嵌在中间, 而是图表影响了很多内容的显示.
不过至少我们需要的图表出现了, 这些细节可以通过样式进行修整, 就不过多介绍了.

修改配置

这里我们的初试已经完成了, 但是仅仅是这样的效果, 怎么修改成我们想显示的数据呢?
我们可以看到之前粘贴的js中有这样的内容:

var option = {
        title: {
            text: '测试下面legend的红色区域不应被裁剪',
            left: 'center'
        },
        color: ["#37A2DA", "#67E0E3", "#9FE6B8"],
        legend: {
            data: ['A', 'B', 'C'],
            top: 50,
            left: 'center',
            backgroundColor: 'red',
            z: 100
        },
        grid: {
            containLabel: true
        },
        tooltip: {
            show: true,
            trigger: 'axis'
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            // show: false
        },
        yAxis: {
            x: 'center',
            type: 'value',
            splitLine: {
                lineStyle: {
                    type: 'dashed'
                }
            }
            // show: false
        },
        series: [{
            name: 'A',
            type: 'line',
            smooth: true,
            data: [18, 36, 65, 30, 78, 40, 33]
        }, {
            name: 'B',
            type: 'line',
            smooth: true,
            data: [12, 50, 51, 35, 70, 30, 20]
        }, {
            name: 'C',
            type: 'line',
            smooth: true,
            data: [10, 30, 31, 50, 40, 20, 10]
        }]
    };

我们可以通过这个option对象修改成我们需要展示的数据, 达到自定义我们的图表.
配置项过多, 我们这里就不一一尝试了, 官方文档提供的配置项填写教程非常简单, 一看就懂.
可以通过: 点击这里查看如何进行配置项的修改.

稍作更新:
以上是使用ECharts制作静态图表展示, 由于简友表示只有静态图表还不够看, 我决定加上添加动态数据的步骤, 确实图表的展示只是静态不符合一般需求.

那么我们开始学习如何再图表配置完成后, 添加新数据.

我们可以看到在之前的静态数据展示的index.js内容中, 我也提到过了, option中的内容才是我们数据展示的内容, 而在Page({})data中我们只添加了ec: {onInit: initChart}这样的一段代码, 这跟option没有直接关系, 我们无法使用微信更新数据使用的setData来进行数据更新, 我当时也思考了很久, 后来还是通过翻阅了echart的官方文档得到了答案, 我们可以通过chart.setOption(option)来进行数据的更新, 上文已经提及了option的作用, 那么这个chart哪来的呢, 下面我们看看如何使用这个api.
我们可以看到我们粘贴到index.js中, 有粘贴入这样的代码(为了代码简洁更易于阅读, 这里我将option中的数据配置省略了):

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

    var option = {
        ...
    };

    chart.setOption(option);
    return chart;
}

我们可以看到initChart函数体中这样的代码:

const chart = echarts.init(canvas, null, {
    width: width,
    height: height
});

可以看到, 我们需要的chart实例在函数体中定义了.
再往下看, 还可以看到函数体中有一个这样的语句chart.setOption(option);这就是ECharts官方文档中让我们使用的设置数据的方法, 大家应该也看明白了, 原来函数体中也是这样设置option(数据)的.
那么我们不难想到, 只要我们在每次从后端请求到数据后, 再将数据写入option中,然后通过chart.setOption(option);就可以实现数据的更新了, 如果加入个定时器, 那么就是可以控制每一段时间获取一次新的数据了并展示到图表中了.

由于其实我还没有这么多数据可以动态请求获取, 感觉这样的逻辑也不难, 只要大家明白如何设置, 那么一定可以通过wx.request请求新数据然后设置.

那么我就用一个按钮来展示一下更新新数据吧. (我们就假装按了按钮其实就是从服务器获取了一次新数据好吧~), 那么我们开始.

还是按着上文的做法, 尽量不更改已有内容(尽管很丑, 但至少不影响我们的学习), 我先在index.js中加入一个可以点击的view, 代码如下:

<!--index.wxml-->
<view class="container">
    <view class="userinfo">
        <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
        <block wx:else>
            <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
            <text class="userinfo-nickname">{{userInfo.nickName}}</text>
        </block>
    </view>

    <!--这里是图表组件的使用-->
    <ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>

    <!-- 加入一个控制图表更新数据的按钮 -->
    <view class="change" bind:tap="changeOption">
        尝试往图表中加入新数据
    </view>

    <view class="usermotto">
        <text class="user-motto">{{motto}}</text>
    </view>
</view>

这个view中我绑定了一个点击(轻触)事件changeOption, 接着我要在index.js中完成他的事件函数体编写.
在编写之前, 我们需要整理一下思路, 我们触发的事件changeOption是在Page({})中编写, 而我们还知道echartsinitChart函数体中, 那么我们无法在Page({})使用echarts实例, 我们需要将它的声明提到initChart函数体外, 这样才能再Page({})中的changeOption里使用到它. 这时候我们可以开始编写changeOption函数了(为了方便阅读, 这里还是将无关的代码省略):

//index.js
//获取应用实例
const app = getApp()
import * as echarts from '../../components/ec-canvas/echarts';

// 将chart声明到这儿作为全局变量使用
let chart;

function initChart(canvas, width, height) {
    chart = echarts.init(canvas, null, {
        width: width,
        height: height
    });
    canvas.setChart(chart);

    var option = {
        title: {
            text: '测试下面legend的红色区域不应被裁剪',
            left: 'center'
        },
        color: ["#37A2DA", "#67E0E3", "#9FE6B8"],
        legend: {
            data: ['A', 'B', 'C'],
            top: 50,
            left: 'center',
            backgroundColor: 'red',
            z: 100
        },
        grid: {
            containLabel: true
        },
        tooltip: {
            show: true,
            trigger: 'axis'
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            // show: false
        },
        yAxis: {
            x: 'center',
            type: 'value',
            splitLine: {
                lineStyle: {
                    type: 'dashed'
                }
            }
            // show: false
        },
        series: [{
            name: 'A',
            type: 'line',
            smooth: true,
            data: [18, 36, 65, 30, 78, 40, 33]
        }, {
            name: 'B',
            type: 'line',
            smooth: true,
            data: [12, 50, 51, 35, 70, 30, 20]
        }, {
            name: 'C',
            type: 'line',
            smooth: true,
            data: [10, 30, 31, 50, 40, 20, 10]
        }]
    };

    chart.setOption(option);
    return chart;
}

Page({

    changeOption() {
        chart.setOption({
            title: {
                text: '测试下面legend的红色区域不应被裁剪',
                left: 'center'
            },
            color: ["#37A2DA", "#67E0E3", "#9FE6B8"],
            legend: {
                data: ['A', 'B', 'C'],
                top: 50,
                left: 'center',
                backgroundColor: 'red',
                z: 100
            },
            grid: {
                containLabel: true
            },
            tooltip: {
                show: true,
                trigger: 'axis'
            },
            xAxis: {
                type: 'category',
                boundaryGap: false,
                data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                // show: false
            },
            yAxis: {
                x: 'center',
                type: 'value',
                splitLine: {
                    lineStyle: {
                        type: 'dashed'
                    }
                }
                // show: false
            },
            series: [{
                name: 'A',
                type: 'line',
                smooth: true,
                data: [18, 36, 65, 30, 78, 40, 33]
            }, {
                name: 'B',
                type: 'line',
                smooth: true,
                data: [12, 50, 51, 35, 70, 30, 20]
            }, {
                name: 'C',
                type: 'line',
                smooth: true,
                data: [10, 30, 31, 50, 40, 20, 10]
            }, {
                name: 'D',
                type: 'line',
                smooth: true,
                data: [1, 3, 2, 5, 4, 7, 6]
            }, {
                name: 'E',
                type: 'line',
                smooth: true,
                data: [10, 20, 30, 40, 50, 60, 70]
            }]
        });
    },

    onShareAppMessage: function(res) {
        ...
    },
    data: {
        motto: 'Hello World',
        userInfo: {},
        hasUserInfo: false,
        canIUse: wx.canIUse('button.open-type.getUserInfo'),
        ec: {
            onInit: initChart
        }
    },
    //事件处理函数
    bindViewTap: function() {
        ...
    },
    onLoad: function() {
        ...
    },
    getUserInfo: function(e) {
        ...
    }
})

简单说一下步骤:

这样的话, 点击view触发事件后更新出来的新数据应该是多出两条新的曲线.

那么我们一起看看效果吧~
编译运行后:

编译后效果展示
点击了view(尝试往图表中加入新数据字样)后:
触发了事件后, 数据更新

那么关于如何进行图表数据的更新, 我们也进行了粗略的了解. 还是那句话啦, 希望大家能有什么疑问可以私信我, 非常感谢提出疑问的简友!

结束

这里我们简单尝试了在微信小程序中使用了ECharts组件完成图表绘制, 感谢ECharts开发团队让我们能快速绘制想要的图表, 这里是他们的官网链接, 大家可以深入学习.

如文中有疑问和错误希望可以提出以供本人修正, 感谢阅读.

上一篇下一篇

猜你喜欢

热点阅读