<script lang="ts" setup name="PieChart"> import type { ECharts } from 'echarts' import { init, number } from 'echarts' import type { Ref } from 'vue' import type { ECBasicOption } from 'echarts/types/dist/shared' import type { pieDataI, pieOption, pieSeriesOption } from './echart-interface' import tdTheme from './theme.json' // 引入默认主题 const props = defineProps({ /** * id */ id: { type: String, default: 'chart', }, /** * 加载中 */ loading: { type: Boolean, default: false, }, /** * 标题 */ title: { type: String, default: '', }, /** * 图例是否显示 */ legend: { type: Object, default: () => { return { show: true, type: 'scroll', orient: 'horizontal', right: '10%', top: 'top', icon: 'circle', itemWidth: 16, itemHeight: 16, itemStyle: { fontSize: 16, }, } }, }, /** * 文本标签是否显示 */ labelShow: { type: Boolean, default: false, }, /** * 图表宽 */ width: { type: String, default: '100%', }, /** * 图表高 */ height: { type: String, default: '100%', }, /** * 饼图的半径[内半径,外半径] */ radius: { type: Array, default: () => { return ['10%', '50%'] }, }, /** * 距离容器右侧距离,默认0,为legend在右侧时做准备 */ right: { type: [Number, String], default: 0, }, /** * 是否要展示成玫瑰图,或玫瑰图类型:radius|area */ roseType: { type: [String, Boolean], default: false, }, /** * 显示值类型:percentage百分比|value数值 */ valueType: { type: String, default: 'percentage', }, /** * 数据,格式为 [{name:'xxx',value:0},...] */ data: { type: Array, default: () => { return [] }, }, /** * 颜色 */ colors: { type: Array, default: () => { return ['#3d7eff', '#caddff'] }, }, /** * 网格配置 */ grid: { type: Object, default: () => { return { top: 0, left: '5%', right: '50%', bottom: 50, containLabel: true, // 是否包含坐标轴的刻度标签 } }, }, /** * 标签文字颜色 */ fontColor: { type: String, default: '#000000', }, /** * 标签格式化 */ labelFormatter: { type: String, default: '', }, /** * 标签位置, outside饼图扇区外侧, inside饼图扇区内部, center饼图中心位置 */ labelPosition: { type: String, default: 'center', }, unit: { type: String, default: '', }, /** * 悬停格式化 */ 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 = { title: [{ text: props.title }], grid: props.grid, // 网格 legend: props.legend, // 图例 toolbox: [{ // feature: { // saveAsImage: { // show: 'true', // icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0', // title: '保存为图片', // type: 'png', // connectedBackgroundColor: '#fff', // name: '', // }, // }, }], tooltip: { show: true, trigger: 'item', formatter: '{b}<br/>数量:{c}' + props.unit + '<br/>占比:{d}%', textStyle: { fontSize: 14, }, }, // 提示框 series: [] as pieSeriesOption[], } // 标题 if (props.title) { option.title = { show: true, text: props.title, textStyle: { fontWeight: 'normal', fontSize: 14, color: '#0b2c5b', }, bottom: 0, left: 'center', } } // 标题 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: 60, right: props.right, itemStyle: { borderColor: '#fff', borderWidth: 1, borderRadius: 8, }, label: { fontSize: 16, }, // label: { // show: false, // position: 'center', // formatter: props.labelFormatter ? props.labelFormatter : (props.valueType == 'percentage' ? '{style1|{b}}\n{style2|{d}%}' : '{style1|{b}}\n{style2|{c}}'), // fontSize: 16, // fontWeight: 'bold', // rich: { // style1: { // color: props.fontColor, // fontSize: 16, // }, // style2: { // color: props.fontColor, // fontWeight: 'bolder', // fontSize: 19, // }, // }, // emphasis: { // show: false, // 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) chart.resize() } } 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%; z-index: 100; } </style>