背景

​ ECharts是由百度开发捐献给Apache的一款基于 JavaScript 的开源可视化图表库,有丰富的图表库、完善的文档,开箱即用,非常方便好用。

效果预览

以下效果中的数据均为虚拟数据。

其中包含饼状图折线图

image-20210925180051481

相关文档

官方示例:https://echarts.apache.org/examples/zh/index.html

官方文档:https://echarts.apache.org/handbook/zh/get-started/

相关依赖
"echarts": "5.1.2"
  • 工具类

utils/index.js

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

mixins/resize.js

import { debounce } from '@/utils'

export default {
  data() {
    return {
      $_sidebarElm: null
    }
  },
  mounted() {
    this.$_initResizeEvent()
    this.$_initSidebarResizeEvent()
  },
  beforeDestroy() {
    this.$_destroyResizeEvent()
    this.$_destroySidebarResizeEvent()
  },
  activated() {
    this.$_initResizeEvent()
    this.$_initSidebarResizeEvent()
  },
  deactivated() {
    this.$_destroyResizeEvent()
    this.$_destroySidebarResizeEvent()
  },
  methods: {
    $_resizeHandler() {
      return debounce(() => {
        if (this.chart) {
          this.chart.resize()
        }
      }, 100)()
    },
    $_initResizeEvent() {
      window.addEventListener('resize', this.$_resizeHandler)
    },
    $_destroyResizeEvent() {
      window.removeEventListener('resize', this.$_resizeHandler)
    },
    $_sidebarResizeHandler(e) {
      if (e.propertyName === 'width') {
        this.$_resizeHandler()
      }
    },
    $_initSidebarResizeEvent() {
      this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
      this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
    },
    $_destroySidebarResizeEvent() {
      this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
    }
  }
}
具体实现

下面组件的变量每一个在官方文档中都有标注,自行去查阅。

饼状环形圆角图(组件编写)
Vue部分
<template>
  <div :class="className" :style="{minHeight:height,width:width}"/>
</template>
Js部分
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'

// 饼状环形圆角图
export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '250px'
    },
    seriesData: {
      type: Array,
      // 默认数据
      default: () => {
        return [
          {
            name: '用户统计',
            type: 'pie',
            radius: ['40%', '70%'],
            avoidLabelOverlap: false,
            itemStyle: {
              borderRadius: 10,
              borderColor: '#fff',
              borderWidth: 2
            },
            label: {
              show: false,
              position: 'center'
            },
            emphasis: {
              label: {
                show: true,
                fontSize: '15',
                fontWeight: 'bold'
              }
            },
            labelLine: {
              show: false
            },
            data: [
              { value: 1048, name: '新增' },
              { value: 735, name: '冻结' },
              { value: 355, name: '活跃' }
            ]
          }
        ]
      }
    }
  },
  data() {
    return {
      chart: null
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, 'roma')
      this.drawChart()
    },
    drawChart() {
      this.chart.setOption({
        tooltip: {
          trigger: 'item',
          // formatter: '{a} <br/>{b} : {c} ({d}%)',
          formatter: '{b} : {c} ({d}%)',
          backgroundColor: 'rgba(255,255,255,0.8)',
          color: 'black',
          borderWidth: '1',
          borderColor: 'gray',
          textStyle: {
            color: 'black'
          }
        },
        legend: {
          left: 'center'
        },
        series: this.seriesData
      })
    }
  }
}
</script>
饼状平铺图(组件编写)
Vue部分
<template>
  <div :class="className" :style="{minHeight:height,width:width}"/>
</template>
Js部分
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'

// 饼状平铺图
export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '300px'
    },
    seriesData: {
      type: Array,
      default: () => {
        return [
          {
            name: '示例数据',
            type: 'pie',
            radius: '50%',
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            },
            itemStyle: {
              normal: {
                label: {
                  show: true,
                  formatter: '{b} : {c} ({d}%)'
                },
                labelLine: { show: true }
              }
            },
            data: [
              { value: 1048, name: '类目一' },
              { value: 735, name: '类目二' },
              { value: 580, name: '类目三' }
            ]
          }
        ]
      }
    }
  },
  watch: {
    seriesData: {
      deep: true,
      handler(val) {
        this.seriesData = val
        this.disposeChart()
        this.initChart()
      }
    }
  },
  data() {
    return {
      chart: null
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  beforeDestroy() {
    this.disposeChart()
  },
  methods: {
    disposeChart() {
      if (!this.chart) {
        return
      }
      this.chart.dispose()
      this.chart = null
    },
    initChart() {
      this.chart = echarts.init(this.$el, 'roma')
      this.drawChart()
    },
    drawChart() {
      this.chart.setOption({
        tooltip: {
          trigger: 'item',
          formatter: '{b} : {c} ({d}%)'
        },
        legend: {
          left: 'center'
        },
        series: this.seriesData
      })
    }
  }
}
</script>
折线堆叠图(组件编写)
Vue部分
<template>
  <div :class="className" :style="{height:height,width:width}"/>
</template>
Js部分
// 折线堆叠图
export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '500px'
    },
    xAxisData: {
      type: Array,
      default: () => {
        return ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
      }
    },
    seriesData: {
      type: Array,
      default: () => {
        return [{
          name: '示例1',
          type: 'line',
          stack: '总量',
          emphasis: {
            focus: 'series'
          },
          areaStyle: {
            // 改变区域颜色
            //color: '#fadb14'
          },
          // itemStyle: {
          //   normal: {
          //     // 折线点颜色
          //     color: '#d4b106',
          //     lineStyle: {
          //       // 折线颜色
          //       color: '#876800'
          //     }
          //   }
          // },
          // 光滑线条
          // smooth: true,
          data: [67, 6213, 66, 67, 78, 632, 1410, 4552, 4512, 555]
        }, {
          name: '示例2',
          type: 'line',
          stack: '总量',
          areaStyle: {},
          emphasis: {
            focus: 'series'
          },
          data: [120, 132, 101, 134, 90, 230, 210, 3466, 67, 36]
        }]
      }
    }
  },
  watch: {
    xAxisData: {
      deep: true,
      handler(val) {
        this.xAxisData = val
      }
    },
    seriesData: {
      deep: true,
      handler(val) {
        this.seriesData = val
        this.disposeChart()
        this.initChart()
      }
    }
  },
  data() {
    return {
      chart: null
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  beforeDestroy() {
    this.disposeChart()
  },
  methods: {
    disposeChart() {
      if (!this.chart) {
        return
      }
      this.chart.dispose()
      this.chart = null
    },
    initChart() {
      this.chart = echarts.init(this.$el, 'roma')
      this.drawChart()
    },
    drawChart() {
      this.chart.setOption({
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            label: {
              backgroundColor: '#6a7985'
            }
          }
        },
        legend: {
          left: 'center'
        },
        toolbox: {
          feature: {
            saveAsImage: {}
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: [
          {
            type: 'category',
            boundaryGap: false,
            data: this.xAxisData
          }
        ],
        yAxis: [
          {
            type: 'value'
          }
        ],
        series: this.seriesData
      })
    }
  }
}
</script>
组件引用(业务代码)
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
  <el-card shadow="always">
    <div slot="header" class="clearfix">
      <span>销售趋势</span>
      <span class="card-div-desc">{{ lineCardTitle }}</span>
      <el-radio-group style="float: right; padding: 3px 0" v-model="lineDataType"
                      size="mini" @change="handleLineChange">
        <el-radio-button label="order">订单数</el-radio-button>
        <el-radio-button label="sale">销售额</el-radio-button>
      </el-radio-group>
    </div>
    <div>
      <LineHeapChart
          height="600px"
          :xAxisData="lineXAxisData"
          :seriesData="lineSeriesData"
      />
    </div>
  </el-card>
</el-col>

import LineHeapChart from '@/views/dashboard/LineHeapChart'
import PieFlatChart from '@/views/dashboard/PieFlatChart'

export default {
  name: 'index',
  components: {
    LineHeapChart,
    PieFlatChart
  },
}

具体的数据结构,在每一个组件里面的插槽位置都有对应的默认数据示例,自行将后端传来的数据转换为默认数据格式传递给组件就可以了。

下载文章代码

https://download.csdn.net/download/zhengjiacheng2016/85242441

(如果帮助到你,感谢关注点赞)

声明:不包含示例图的全部布局样式代码,需要的自己根据项目风格编写布局,放入Chart即可,像[ 组件引用(业务代码) ],部分一样,简单的用[el-card] 组件包装。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐