168 lines
3.4 KiB
Vue

<template>
<div class="ring-chart" ref="chartRef"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
const props = defineProps({
chartData: {
type: Array,
default: () => [
{ name: '蓝色', value: 13, color: '#40a9ff' },
{ name: '橙色', value: 40.2, color: '#ff7a45' },
{ name: '黄色', value: 22, color: '#ffc53d' },
{ name: '红色', value: 8, color: '#ff4d4f' },
],
},
centerText: {
type: String,
default: '风险\n状况',
},
});
const chartRef = ref(null);
let chartInstance = null;
const initChart = () => {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%',
},
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
itemWidth: 10,
itemHeight: 10,
textStyle: {
color: '#fff',
fontSize: 12,
},
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle',
})),
},
series: [
{
name: '风险状况',
type: 'pie',
radius: ['45%', '65%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{c}%',
color: '#fff',
fontSize: 12,
},
labelLine: {
show: true,
length: 15,
length2: 10,
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)',
},
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold',
},
},
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color,
},
})),
},
{
type: 'pie',
radius: ['0%', '35%'],
center: ['40%', '50%'],
silent: true,
label: {
show: true,
position: 'center',
formatter: props.centerText,
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
lineHeight: 24,
},
data: [{ value: 1, name: '', itemStyle: { color: 'transparent' } }],
},
],
};
chartInstance.setOption(option);
};
const updateChart = () => {
if (!chartInstance) return;
const option = {
legend: {
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle',
})),
},
series: [
{
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color,
},
})),
},
{
label: {
formatter: props.centerText,
},
},
],
};
chartInstance.setOption(option);
};
const handleResize = () => {
chartInstance?.resize();
};
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
watch(() => props.chartData, updateChart, { deep: true });
watch(() => props.centerText, updateChart);
</script>
<style lang="scss" scoped>
.ring-chart {
width: 100%;
height: 100%;
}
</style>