You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.2 KiB

2 years ago
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from '@/mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: ''
},
height: {
type: String,
default: '100px'
},
width: {
type: String,
default: '100px'
},
percent: {
type: [Number, String],
default: 100
},
chartData: {
type: Array,
default: () => []
},
title: {
type: String,
default: '标题'
}
},
data() {
return {
flag: true,
chart: null
}
},
computed: {
options() {
return {
legend: {
show: true,
bottom: 0,
left: 'center',
orient: 'horizontal',
itemWidth: 8,
itemHeight: 5
},
color: ['#446df6', '#f2a93f', '#56b7f9'],
series: [
{
type: 'pie',
radius: ['50%', '70%'],
center: ['50%', '36%'],
padAngle: 4,
itemStyle: {
borderRadius: 10,
padding: 10
},
label: {
show: true,
position: 'center',
formatter: `{b}\n{d}%`
},
avoidLabelOverlap: true, // 是否启用防止标签重叠策略
emphasis: { // 高亮,即鼠标经过时的样式
scale: true // 表示不放大item
},
labelLine: {
show: false
},
data: (() => {
if (this.percent || this.percent === 0) {
return [
{ value: parseFloat(this.percent), name: `${this.title}` },
{ value: 100 - parseFloat(this.percent), name: `${this.title}` }
]
} else {
return this.chartData
}
})()
}
],
graphic: {
elements: []
}
}
}
},
watch: {
chartData() {
this.setOptions()
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons')
this.setOptions()
},
setOptions() {
this.chart?.setOption(this.options)
// this.setGraphics()
},
setGraphics() {
const getPointOnCircle = (angle, radiusPercent) => {
const radian = (angle - 90 - 12) * Math.PI / 180
const radius = this.chart.getWidth() / 2 * radiusPercent / 100
const x = this.chart.getWidth() / 2 + Math.cos(radian) * radius
const y = this.chart.getHeight() / 2 + Math.sin(radian) * radius - this.chart.getHeight() * 0.1
return { x: x, y: y }
}
const graphicElements = []
let total = 0
if (!this.options?.series[0]?.data) return
this.options?.series[0]?.data.forEach(function(item) {
total += item.value
})
let startAngle = 0
this.options?.series[0]?.data.forEach(function(item) {
const angle = (item.value / total) * 360
const endAngle = startAngle + angle
const middleAngle = (startAngle + endAngle) / 2
// 计算开始和结束点的位置
const pointStart = getPointOnCircle(middleAngle - angle / 2, 60)
const pointEnd = getPointOnCircle(middleAngle + angle / 2, 60)
// 添加小圆的装饰
graphicElements.push({
type: 'circle',
shape: {
cx: pointStart.x,
cy: pointStart.y,
r: 3
},
style: {
fill: '#fff'
},
z: 100
})
graphicElements.push({
type: 'circle',
shape: {
cx: pointEnd.x,
cy: pointEnd.y,
r: 3
},
style: {
fill: '#fff'
},
z: 100
})
startAngle += angle
})
this.chart.setOption({
graphic: {
elements: graphicElements
}
})
}
}
}
</script>
<style scoped lang="scss">
</style>