1、echarts.js
将饼图封装成一个组件
<template>
<!-- 每一个图表都有自己唯一的id,所有需要动态传入。 -->
<div
:id="id"
:style="style"/>
</template>
<script>
import echarts from 'echarts'
// 引入 echarts 主模块。
export * from 'echarts/src/echarts'
// 引入饼图。
import 'echarts/src/chart/pie'
export default {
props: {
id: {
type: String,
default: ''
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: ''
},
chartData: {
type: Object,
default: () => {}
}
},
data() {
return {
MyEcharts: '' // echarts实例
}
},
computed: {
style() {
return {
height: '300px',
width: '100%'
//可以使用父组件传递过来的值 height width
//height:this.height,
//width:this.width
}
},
optionData() {
return this.chartData
}
},
mounted() {
this.InitCharts()
},
methods: {
InitCharts() {
this.MyEcharts = echarts.init(document.getElementById(this.id))
this.MyEcharts.clear() // 适用于大数据量的切换时图表绘制错误,先清空在重绘
console.log(this.optionData, '传入的值item')
if (this.optionData) {
var options = {
name: this.optionData.columnName,//统计表格列的表头名
data: []
}
options.data = this.optionData.countObjects.map(item => {
return { name: item.name, value: item.count }
})
const nameArr = options.data.map(item => {
return item.name
})
const setChart = this.drawChart(options, nameArr)
console.log(setChart, '图表配置数据')
this.MyEcharts.setOption(setChart, true) // 设置为true可以是图表切换数据时重新渲染
}
// 以下这种方法,当一个页面有多个图表时,会有一个bug那就是只有一个图表会随着窗口大小变化而变化,解决办法。
// window.onresize = () => {
// this.MyEcharts.resize()
// }
// 当窗口变化时随浏览器大小而改变
// 以下为上边的bug的解决方案。以后用这种方案,放弃上一种。
const _this = this
window.addEventListener('resize', function() {
_this.MyEcharts.resize()
})
},
drawChart(options, nameArr) {
const option = {
// 图标的标题
title: {
text: this.getName(this.optionData.columnName),//需要过滤显示 不然显示的是表格列的字段名
subtext: '统计图',
// x 设置水平安放位置,默认左对齐,可选值:'center' ¦ 'left' ¦ 'right' ¦ {number}(x坐标,单位px)
x: 'center',
// y 设置垂直安放位置,默认全图顶端,可选值:'top' ¦ 'bottom' ¦ 'center' ¦ {number}(y坐标,单位px)
y: 'top',
// itemGap设置主副标题纵向间隔,单位px,默认为10,
itemGap: 20,
// backgroundColor: '#EEE',标题背景颜色
// 主标题文本样式设置
textStyle: {
fontSize: 18,
fontWeight: 'bolder',
color: '#49ADF4'
},
// 副标题文本样式设置
subtextStyle: {
fontSize: 14,
color: '#8B2323'
}
},
// // 图例 本例中未使用
// legend: {
// // orient 设置布局方式,默认水平布局,可选值:'horizontal'(水平) ¦ 'vertical'(垂直)
// orient: 'vertical',
// // x 设置水平安放位置,默认全图居中,可选值:'center' ¦ 'left' ¦ 'right' ¦ {number}(x坐标,单位px)
// x: 'left',
// // y 设置垂直安放位置,默认全图顶端,可选值:'top' ¦ 'bottom' ¦ 'center' ¦ {number}(y坐标,单位px)
// y: 'center',
// itemWidth: 24, // 设置图例图形的宽
// itemHeight: 18, // 设置图例图形的高
// textStyle: {
// color: '#666' // 图例文字颜色
// },
// // itemGap设置各个item之间的间隔,单位px,默认为10,横向布局时为水平间隔,纵向布局时为纵向间隔
// itemGap: 30,
// backgroundColor: '#eee', // 设置整个图例区域背景颜色
// data: nameArr
// },
// 鼠标悬浮提示框
tooltip: {
// trigger 设置触发类型,默认数据触发,可选值:'item' ¦ 'axis'
trigger: 'item',
showDelay: 20, // 显示延迟,添加显示延迟可以避免频繁切换,单位ms
hideDelay: 20, // 隐藏延迟,单位ms
backgroundColor: 'rgba(255,0,0,0.7)', // 提示框背景颜色
textStyle: {
fontSize: '16px',
color: '#000' // 设置文本颜色 默认#FFF
},
position: 'inside', //设置提示框位置位于鼠标所在图形的内部中心位置
/* 这种方法只在设置 只有在 trigger: 'item' 的时候才有效
'inside' 鼠标所在图形的内部中心位置
'top' 鼠标所在图形上侧
'left' 鼠标所在图形左侧
'right' 鼠标所在图形右侧
'bottom' 鼠标所在图形底侧
*/
// formatter设置提示框显示内容
// {a}指series.name {b}指series.data的name
// {c}指series.data的value {d}%指这一部分占总数的百分比
formatter: '{a}
{b} : {c}个 ({d}%)'
},
// 设置饼状图每个颜色块的颜色
// color: ['red', 'orange', 'green', 'blue', 'indigo', 'purple'],
normal: {
// 自定义颜色
color: function(params) {
var colorList = [
'red', 'orange', '#49ADF4', '#00FFFF', '#00FF00', '#FFFF00', '#FF8C00', '#FF0000', '#FE8463'
]
return colorList[params.dataIndex]
}
},
series: [
{
name: this.getName(options.name),
type: 'pie',
redius: '55%',
data: options.data,
// itemStyle 设置饼状图扇形区域样式
itemStyle: {
normal: {
label: {
show: true,
formatter: '{b} : {c} ({d}%)'
},
labelLine: { show: true },
// emphasis:英文意思是 强调;着重;(轮廓、图形等的)鲜明;突出,重读
// emphasis:设置鼠标放到哪一块扇形上面的时候,扇形样式、阴影
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(30, 144, 255,0.5)'
}
}
},
// 设置值域的那指向线
labelLine: {
normal: {
show: false // show设置线是否显示,默认为true,可选值:true ¦ false
}
},
// 设置值域的标签
label: {
normal: {
position: 'inner', // 设置标签位置,默认在饼状图外 可选值:'outer' ¦ 'inner(饼状图上)'
// formatter: '{a} {b} : {c}个 ({d}%)' 设置标签显示内容 ,默认显示{b}
// {a}指series.name {b}指series.data的name
// {c}指series.data的value {d}%指这一部分占总数的百分比
formatter: '{c}'
}
}
}
]
}
return option
},
getName() {
console.log(arguments[0], '传递名字')
switch (arguments[0]) {
case 'type':
return '类型'
case 'distance':
return '距离'
case 'price':
return '单价'
case 'charge':
return '里程费'
case 'objectType':
return '对象类型'
case 'grade':
return '等级'
case 'company':
return '公司'
case 'status':
return '状态'
default :
return ''
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
2、vue中使用
将上一个页面选择需要统计的表格列数组传递到后台,根据返回的统计数据循环绘制出饼图和表格
<template>
<div class="form-box" >
<h3 class="form-title">统计列表</h3>
<!-- 按钮 -->
<div class="btn-row">
<el-button
size="mini"
icon="el-icon-back"
plain
@click="goBack">返回</el-button>
</div>
<!-- 表格 -->
<el-row :gutter="24">
<el-col v-for="(item,index) in countData" :xs="24" :sm="12" :lg="6" :key="index" style="margin-top:20px;height:300px">
<pieChart :id="`chart+${index}`" :style="{width: '100%', height: '380px'}" :chart-data="item"/>
<el-table
ref="table"
:data="item.countObjects"
height="300"
resizable
border
style="width: 100%">
<!--数据源-->
<el-table-column :label="getName(item.columnName)" header-align="center">
<el-table-column align="center" prop="name" label="名称">
<template slot-scope="scope">
<template v-if="item.columnName==='siteStatus'">{{ scope.row.name|filterApprovalStatus }}</template>
<template v-else>
<span>{{ scope.row.name }}</span>
</template>
</template>
</el-table-column>
<el-table-column align="center" width="100px" prop="count" label="数量"/>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
</template>
<script>
import { count } from '@/api/public'
import initDict from '@/mixins/initDict'
import statusDict from '@/mixins/statusDict'
import pieChart from '@/views/components/pieChart'
export default {
components: { pieChart },
mixins: [initDict, statusDict],
data() {
return {
countData: [],
name: {}
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.name = vm.$route.query.data
if (vm.name) {
vm.getData()
}
})
},
beforeRouteLeave(to, from, next) {
next()
},
created() {
// 获取数据字典
this.getDictMap('inside_company,site_status,first_type')
},
methods: {
// 传递需要统计的字段数组 this.name
getData() {
count(this.name).then(res => {
this.countData = res
})
this.getDictMap('inside_company,site_status,first_type')
},
getName() {
console.log(arguments[0], '传递名字')
switch (arguments[0]) {
case 'type':
return '类型'
case 'distance':
return '距离'
case 'price':
return '单价'
case 'charge':
return '里程费'
case 'objectType':
return '对象类型'
case 'grade':
return '等级'
case 'company':
return '公司'
case 'status':
return '状态'
default :
return ''
}
},
goBack() {
this.$router.go(-1)
}
}
}
</script>
<style lang="scss" >
@import "@/styles/form.scss";
</style>
<style scoped>
li{
margin: 12px 0;
}
</style>