<template> <div :id="id" :style="`width:${curWidth==0?'100%':curWidth};height:${curHeight==0?'100%':curHeight}`" > </div> </template> <script> /** * @author 王晓颖 * @date 2020/08/18 * @Description 普通饼图 * @props 数据格式:{ * id: '', width: 0, height: 0, xAxisData:[], seriesData: [] } * */ export default { name: 'SimplePieChart', props: { id: { // id type: String, default: 'simplePieChart' }, width: { // 宽 type: Number | String, default: '100%' }, height: { // 高 type: Number | String, default: '100%' }, radius: { // 饼图的半径[内半径,外半径] type: Array, default: () => { return ['30%', '45%'] } }, fontFamily: { // 值显示字体 type: String, default: '' }, roseType: { // 是否要展示成玫瑰图,或玫瑰图类型:radius|area type: String | Boolean, default: false }, colors: { // 颜色组 type: Array, default: () => { return ['#95a2ff', '#fa8080', '#ffc076', '#fae768', '#87e885', '#3cb9fc', '#73abf5', '#cb9bff', '#0078d4', '#90ed7d', '#f7a35c', '#8085e9'] } }, fontColor: { // 标签文字颜色 type: String, default: '#ffffff' }, valueType: { // 显示值类型:percentage百分比|value数值 type: String, default: 'percentage' }, labelShow: { type: Boolean, default: true }, labelFormatter: { type: String, default: '' }, hoverFormatter: { type: String, default: '{b}<br/>{c}<br/>{d}%' }, seriesData: { // 数据 type: Array, default: () => { return [] } }, rotateInterval: { // 轮播间隔时间(ms) type: Number, default: 3000 }, isRotate: { // 是否开启轮播 type: Boolean, default: false }, activeFontColor: { // 激活标签字体颜色 type: String, default: '#fff' }, labelLineColor: { // 标签线颜色 type: String, default: '#ccc' }, labelLineWidth: { // 标签线宽度 type: Number, default: 1.5 } }, data () { return { rotateIndex: 0, rotateTimer: null, activeLabelIndex: -1, isMouseOver: false, // 鼠标是否悬停 hoveredIndex: -1, // 鼠标悬停的数据项索引 curWidth: this.width, curHeight: this.height, option: { tooltip: { trigger: 'item', formatter: this.hoverFormatter, textStyle: { fontSize: 15 } }, grid: { top: '10%', left: '5%', right: '5%', bottom: 20, containLabel: true // 是否包含坐标轴的刻度标签 }, // 网格 color: this.colors, series: [ { animationType: 'expansion', // 沿圆弧展开效果 expansion|scale type: 'pie', avoidLabelOverlap: true, // 是否启用防止标签重叠策略 roseType: this.roseType, // 玫瑰图类型 radius: this.radius, // 饼图的半径[内半径,外半径] center: ['50%', '50%'], // 圆心坐标[横坐标,纵坐标] startAngle: 140, label: { show: this.labelShow, formatter: this.labelFormatter, fontSize: 19, lineHeight: 19, rich: { style1: { color: this.fontColor, fontSize: 16 }, style2: { fontWeight: 'bolder', fontSize: 19, fontFamily: this.fontFamily } }, emphasis: { show: true, textStyle: { fontSize: 17, fontWeight: 'bold' } } }, labelLine: { length: 10, length2: 15 }, data: [ // {value:34, name:'申报立案'}, ] } ] } } }, watch: { width (newVal, oldVal) { this.curWidth = newVal this.refreshEchart() }, height (newVal, oldVal) { this.curHeight = newVal this.refreshEchart() }, seriesData (newVal, oldVal) { this.option.series[0].data = newVal this.refreshEchart() } }, computed: { // 动态计算标签格式化函数 labelFormatter () { return (params) => { // 只在非鼠标悬停状态下显示当前轮播项的标签 if (!this.isMouseOver && params.dataIndex === this.activeLabelIndex) { return `${params.name}\n${params.value} (${params.percent}%)` } return '' // 鼠标悬停时或非当前项不显示标签 } } }, mounted () { if (this.seriesData && this.seriesData.length) { // 格式化 if (this.labelFormatter) { this.option.series[0].label.formatter = this.labelFormatter } else { if (this.valueType === 'percentage') { this.option.series[0].label.formatter = '{style1|{b}}\n{style2|{d}%}' } else if (this.valueType === 'value') { this.option.series[0].label.formatter = '{style1|{b}}\n{style2|{c}}' } } this.option.series[0].data = this.seriesData this.initEchart() } if (this.isRotate && this.seriesData && this.seriesData.length > 1) { this.startRotation() } }, beforeDestroy () { this.stopRotation() // 组件销毁前停止轮播 }, methods: { // refreshEchart () { // if (this.curWidth && this.curHeight && this.seriesData && this.xAxisData) { // this.initEchart() // } // }, refreshEchart () { if (this.curWidth && this.curHeight && this.seriesData) { // 去掉多余的xAxisData判断(饼图不需要xAxisData) this.initEchart() } }, // initEchart () { // const _div = document.getElementById(this.id) // setTimeout(() => { // let myChart = this.$echarts.init(this.$el) // myChart.setOption(this.option, true) // window.onresize = myChart.resize // }, 500) // } // 开始轮播 startRotation () { if (this.rotateTimer) clearInterval(this.rotateTimer) this.rotateTimer = setInterval(() => { // 仅在鼠标未悬停时更新轮播 if (!this.isMouseOver) { this.rotateIndex = (this.rotateIndex + 1) % this.seriesData.length this.updateActiveLabel(this.rotateIndex) } }, this.rotateInterval) }, // 停止轮播 stopRotation () { if (this.rotateTimer) { clearInterval(this.rotateTimer) this.rotateTimer = null } }, // 更新激活的标签 updateActiveLabel (index) { const chart = this.$echarts.getInstanceByDom(this.$el) if (chart) { this.activeLabelIndex = index // 更新标签配置 chart.setOption({ series: [{ data: this.seriesData.map((item, i) => ({ ...item, label: { show: !this.isMouseOver && i === index, formatter: this.labelFormatter, fontSize: 14, fontWeight: 'bold', // color: this.activeFontColor, borderRadius: 4 }, labelLine: { show: !this.isMouseOver && i === index, // 明确控制显示/隐藏 length: this.isMouseOver ? 0 : 12, length2: this.isMouseOver ? 0 : 15, lineStyle: { // color: this.labelLineColor, // width: this.labelLineWidth } } })) }] }) // 第二个参数设为true,强制覆盖配置 // 取消上一项的高亮(避免残留) const prevIndex = (index - 1 + this.seriesData.length) % this.seriesData.length; chart.dispatchAction({ type: 'downplay', seriesIndex: 0, dataIndex: prevIndex }) } }, // 重写initEchart方法 initEchart () { const _div = document.getElementById(this.id) setTimeout(() => { let myChart = this.$echarts.init(this.$el) // 修改默认配置 const option = { ...this.option, tooltip: { show: true, // 启用tooltip trigger: 'item', formatter: '{b}<br/>{c} ({d}%)', backgroundColor: 'rgba(36, 37, 51, .6)', textStyle: { color: '#fff' } // extraCssText: 'box-shadow: 0 0 10px rgba(0,0,0,0.15);' }, series: [{ ...this.option.series[0], label: { // show: false // 默认不显示标签 }, labelLine: { // show: false // 默认不显示标签线 } }] } myChart.setOption(option, true) // 窗口大小变化时重绘图表 window.addEventListener('resize', myChart.resize) // 鼠标悬停事件 myChart.on('mouseover', (params) => { this.isMouseOver = true this.hoveredIndex = params.dataIndex // 停止轮播 this.stopRotation() // 隐藏所有标签和标签线 this.updateActiveLabel(this.activeLabelIndex) // 显示tooltip myChart.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: params.dataIndex }) }) // 鼠标移出事件 myChart.on('mouseout', () => { this.isMouseOver = false this.hoveredIndex = -1 // 恢复轮播 this.startRotation() // 隐藏tooltip myChart.dispatchAction({ type: 'hideTip' }) }) // 启动轮播 if (this.isRotate && this.seriesData && this.seriesData.length > 1) { this.startRotation() } }, 500) } } } </script> <style scoped> </style>