<script lang="ts" setup name="PieChart"> import * as echarts from 'echarts/core' import type { ECharts } from 'echarts' import { init } from 'echarts' import type { Ref } from 'vue' import type { ECBasicOption } from 'echarts/types/dist/shared' import { Grid } from '@element-plus/icons-vue' import type { lineSeriesOption, pieDataI, pieOption, pieSeriesOption } from './echart-interface' import tdTheme from './theme.json' // 引入默认主题 import { formatColor, getAlphaColor } from './utils' const props = defineProps({ /** * id */ id: { type: String, default: 'chart', }, /** * 加载中 */ loading: { type: Boolean, default: false, }, /** * 标题 */ title: { type: String, default: '', }, /** * 图例是否显示 */ legend: { type: Object, default: () => { return { show: false, orient: 'vertical', right: '20%', top: 'center', icon: 'circle', itemWidth: 12, itemHeight: 12, itemStyle: { fontSize: 18, }, } }, }, /** * 文本标签是否显示 */ labelShow: { type: Boolean, default: true, }, /** * 图表宽 */ width: { type: String, default: '100%', }, /** * 图表高 */ height: { type: String, default: '100%', }, /** * 饼图的半径[内半径,外半径] */ radius: { type: Array, default: () => { return ['30%', '45%'] }, }, /** * 是否要展示成玫瑰图,或玫瑰图类型:radius|area */ roseType: { type: [String, Boolean], default: false, }, /** * 显示值类型:percentage百分比|value数值 */ valueType: { type: String, default: 'percentage', }, /** * 数据,格式为 [{name:'xxx',value:0},...] */ data: { type: Array<pieDataI>, default: () => { return [] }, }, /** * 颜色 */ colors: { type: Array, default: () => { return ['#3d7eff', '#caddff'] }, }, /** * 网格配置 */ grid: { type: Object, default: () => { return { top: '10%', left: '5%', right: '5%', bottom: 20, containLabel: true, // 是否包含坐标轴的刻度标签 } }, }, /** * 标签文字颜色 */ fontColor: { type: String, default: '#000000', }, /** * 标签格式化 */ labelFormatter: { type: String, default: '', }, /** * 标签位置, outside饼图扇区外侧, inside饼图扇区内部, center饼图中心位置 */ labelPosition: { type: String, default: 'center', }, /** * 悬停格式化 */ hoverFormatter: { type: String, default: '{b}<br/>数量:{c}<br/>占比:{d}%', }, }) // 图表对象 let chart: ECharts const chartRef: Ref<HTMLElement | null> = ref(null) // 监听数据变化 watch( [() => props.data], ([newNums], [oldNums]) => { refreshChart() }, { immediate: true, deep: true, }, ) // 构建option function buildOption() { const option: pieOption = { grid: props.grid, // 网格 legend: props.legend, // 图例 tooltip: { show: true, trigger: 'item', formatter: props.hoverFormatter, textStyle: { fontSize: 15, }, }, // 提示框 series: [] as pieSeriesOption[], } // 标题 if (props.title) { option.title = { show: true, text: props.title, } } // 标题 if (props.colors) { option.color = props.colors as string[] } // 数据 if (props.data) { const series: pieSeriesOption = { animationType: 'expansion', // 沿圆弧展开效果 expansion|scale type: 'pie', avoidLabelOverlap: true, // 是否启用防止标签重叠策略 roseType: props.roseType, // 玫瑰图类型 radius: props.radius as string[], // 饼图的半径[内半径,外半径] center: ['50%', '50%'], // 圆心坐标[横坐标,纵坐标] startAngle: 140, label: { show: props.labelShow, position: 'center', formatter: props.labelFormatter ? props.labelFormatter : (props.valueType == 'percentage' ? '{style1|{b}}\n{style2|{d}%}' : '{style1|{b}}\n{style2|{c}}'), fontSize: 22, fontWeight: 'bolder', rich: { style1: { color: props.fontColor, fontSize: 16, }, style2: { color: props.fontColor, fontWeight: 'bolder', fontSize: 19, }, }, emphasis: { show: true, textStyle: { fontSize: 22, fontWeight: 'bold', }, }, }, data: props.data, } option.series = [series] } return option } // 初始化图表 function initChart() { chart = init(chartRef.value as HTMLElement, tdTheme) chart.setOption({}) } // 刷新图表 function refreshChart() { if (chart) { const option = buildOption() chart.setOption(option as unknown as ECBasicOption, true) } } window.addEventListener('resize', () => { chart.resize() }) onMounted(() => { initChart() }) </script> <template> <div :id="id" ref="chartRef" v-loading="loading" class="chart" :style="{ height, width }" /> </template> <style lang="scss" scoped> .chart { width: 100%; height: 100%; } </style>