这篇文章主要讲了echarts在vue+iview中的一个应用(柱状图)和在实现过程中遇到的问题,如何设置数据以及如何解决参数动态更新效果。

需求

根据所选时间区间和勾选的参数要素生成响应的图表,单参数图表和多参数图表。

分析

  1. 时间区间格式 传给后台的值 [‘2020-01-15’, ‘2020-02-15’]
  2. 勾选参数:将参数的中英文字段对应做成字典,使用iview的Checkbox组件,勾选对应的参数直接获取到参数字段组成的数组,便于生成对应的报表
  3. 两种图表,单一元素的,多元素混合的。需要两个不同的配置项模板

实施

  1. 找模板

    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
    // 单元素柱状图模板 在A,B,C 处处理数据
    optionTpl: {
    title: {
    text: ''
    },
    tooltip: {
    trigger: 'axis',
    axisPointer: { // 坐标轴指示器,坐标轴触发有效
    type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
    }
    },
    grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true // grid 区域是否包含坐标轴的刻度标签
    },
    legend: {
    data: [] // A 单元素标题
    },
    xAxis: {
    data: [], // B 时间轴数据 ['202001', '202002']
    nameLocation: 'end', //坐标轴名称显示位置。
    axisLabel: { //坐标轴刻度标签的相关设置。
    interval: 0, // 设置成 0 强制显示所有标签。如果设置为 1,表示『隔一个标签显示一个标签』,如果值为 2,表示隔两个标签显示一个标签,以此类推。
    rotate: "30" // x轴文字旋转角度
    }
    },
    yAxis: {},
    series: [] // C 参数数据放在这里
    // series: [{
    // name: '累计融资金额',
    // type: 'bar',
    // data: [5, 20, 36, 10, 10, 100, 120, 150, 30, 80, 50, 130]
    // }]
    },

    // 多元素柱状图模板 A,B处处理数据
    option2Tpl: {
    legend: {},
    // color: ['#3398DB', '#C0504D', '#9BBB59'],
    tooltip: {
    trigger: 'axis',
    axisPointer: { // 坐标轴指示器,坐标轴触发有效
    type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
    }
    },
    grid: { //直角坐标系内绘图网格
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
    },
    dataset: {
    source: [] // A 需要展示的数据
    // ['product', '已实现收入', '待收入', '还款'],
    // ['202001', 43.3, 85.8, 93.7],
    // ['202002', 83.1, 73.4, 55.1],
    // ['202003', 86.4, 65.2, 82.5],
    // ['202004', 72.4, 53.9, 39.1],
    // ['202005', 90.4, 30.9, 66.1],
    },
    xAxis: {
    type: 'category',
    nameLocation: 'end', //坐标轴名称显示位置。
    axisLabel: { //坐标轴刻度标签的相关设置。
    interval: 0,
    rotate: "0"
    }
    },
    yAxis: {},
    series: [] // 有几个图生成 几个type
    // series: [
    // {type: 'bar'},
    // {type: 'bar'},
    // {type: 'bar'}
    // ]
    },
  2. html

    1
    2
    3
    4
    5
    6
    <!-- 动态生成id,为 ECharts 准备一个具备高宽的 DOM 容器 -->
    <Row>
    <Col span="12" v-for="(k, index) in allSelPam" :key="index">
    <div :id="`dom_${k}`" style="height: 320px;width: 100%;"></div>
    </Col>
    </Row>
  3. javascript

    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
    // 在查询方法中,生成图标dom元素 this.selData是选中的参数组成的数组
    // 使用固定的 'allCharts' 作为所用参数综合图表的参数
    this.allSelPam = this.selData.length > 0? ['allCharts', ...this.selData]: []

    // 多参数图表
    setMultipleChart: function (data) {
    let vm = this
    let selData = ApiUtils.pureData(vm.selData)
    let product = ['product']
    let source = []
    let series = []
    let chartData = {allCharts: {}}
    data.forEach((item, idx) => {
    let yData = [item.loanDate]
    selData.forEach(pam => {
    yData.push(item[pam])
    if (idx === 0) {
    let tit = ApiUtils.valueToText(pam, 'dict', 'BUSINESS_SUM_PAM')
    product.push(tit)
    series.push({type: 'bar'})
    }
    })
    source.push(yData)
    })
    source.unshift(product)
    let option = ApiUtils.pureData(vm.option2Tpl)
    option.dataset.source = source
    option.series = series
    chartData['allCharts'].option = option
    return chartData
    },

    // 单参数图标
    setSingleChart: function (data) {
    let vm = this
    let chartData = {}
    this.selData.forEach(pam => {
    chartData[pam] = {}
    let xData = []
    let yData = []
    data.forEach(item => {
    if (item[pam]) {
    yData.push(item[pam])
    xData.push(item.loanDate)
    }
    })
    chartData[pam].option = ApiUtils.pureData(vm.optionTpl)
    let tit = ApiUtils.valueToText(pam, 'dict', 'BUSINESS_SUM_PAM')
    chartData[pam].option.legend.data = [tit]
    chartData[pam].option.xAxis.data = xData
    chartData[pam].option.series = [{
    name: tit,
    type: 'bar',
    data: yData
    }]
    })
    return chartData
    },

    // 根据视口大小动态变化图表
    resize() {
    this.allSelPam.forEach(key => {
    this.chartMap.get(key).resize()
    })
    },

    // 初始化echarts
    initChart: function (chartData) {
    let vm = this
    vm.chartMap.clear()
    Object.keys(chartData).map((key) => {
    let chart = document.getElementById(`dom_${key}`)
    let myChart = echarts.init(chart)
    vm.chartMap.set(key, myChart)
    // 注意 setOption 参数中的 true 保证了图表能及时更新, 如果不使用true还可以使用
    // myChart.clear() 每次都重新初始化图表,这和setOption中设置true效果一样,否则
    // 数据更新了但是图表没有重绘
    myChart.setOption(chartData[key].option, true)
    })
    tools.on(window, 'resize', vm.resize)
    },

    // 在ajax获取数据后初始化图表
    let option = this.setSingleChart(data)
    let option2 = this.setMultipleChart(data)
    let chartOptions = Object.assign({}, option, option2)
    this.initChart(chartOptions)

    // 关闭图表resize
    beforeDestroy() {
    tools.off(window, 'resize', this.resize)
    }
  4. 工具方法

    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
    /** 
    * tools
    * @description 绑定事件 on(element, event, handler)
    */
    export const on = (function () {
    if (document.addEventListener) {
    return function (element, event, handler) {
    if (element && event && handler) {
    element.addEventListener(event, handler, false)
    }
    }
    } else {
    return function (element, event, handler) {
    if (element && event && handler) {
    element.attachEvent('on' + event, handler)
    }
    }
    }
    })()

    /**
    * @description 解绑事件 off(element, event, handler)
    */
    export const off = (function () {
    if (document.removeEventListener) {
    return function (element, event, handler) {
    if (element && event) {
    element.removeEventListener(event, handler, false)
    }
    }
    } else {
    return function (element, event, handler) {
    if (element && event) {
    element.detachEvent('on' + event, handler)
    }
    }
    }
    })()

备注

echartsInstance.setOption

设置图表实例的配置项以及数据,万能接口,所有参数和数据的修改都可以通过 setOption 完成,ECharts 会合并新的参数和数据,然后刷新图表。如果开启动画的话,ECharts 找到两组数据之间的差异然后通过合适的动画去表现数据的变化。

注: ECharts 2.x 中的通过 addData , setSeries 方法设置配置项的方式将不再支持,在 ECharts 3 中统一使用 setOption,可以参考上面示例。

参数:

  • option

    图表的配置项和数据,具体见配置项手册

  • notMerge

    可选,是否不跟之前设置的 option 进行合并,默认为 false,即合并。

  • lazyUpdate

    可选,在设置完 option 后是否不立即更新图表,默认为 false,即立即更新。

  • silent

    可选,阻止调用 setOption 时抛出事件,默认为 false,即抛出事件。