2025-05-16 17:43:53 +08:00

182 lines
4.3 KiB
Vue

<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script>
import { ref, reactive, watch, watchEffect } from 'vue';
import { cloneDeep } from 'lodash';
import { useEcharts } from '@/hooks/useEcharts';
export default {
name: 'CustomEchartTriangle',
props: {
chartData: {
type: Array,
default: () => [],
},
size: {
type: Object,
default: () => {},
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: 'calc(100vh - 78px)',
},
activeIndex: {
type: Number,
default: 1,
},
},
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref(null);
const { setOptions, getInstance, resize, startAutoPlay } = useEcharts(chartRef);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: '#35d0c0',
formatter: (data) => {
const params = data.data;
let str = `<div class="custom-echarts-tips">
<span>${params.name}</span><br/>
<span>${params.reaVal}%</span>
</div>`;
return str;
},
},
series: [
{
zlevel: 1,
name: '漏斗图',
type: 'funnel',
animation: true, // 开启动画
animationDuration: 500, // 过渡时间(毫秒)
animationEasing: 'cubicOut', // 缓动效果
top: '11%',
left: 'center',
width: '25%',
sort: 'ascending',
gap: 0,
label: {
show: false,
position: 'outside',
width: '200px',
align: 'right',
formatter: function (params) {
if (!params.data.reaVal) return '';
let arr = [`{a|${params.data.name}}`, `{b| ${params.data.reaVal}%}`];
return arr.join('\n');
},
rich: {
a: { color: '#fff', fontSize: '16px' },
b: { color: '#05FCC6', fontSize: '16px', marginTop: '10px' },
},
verticalAlign: 'middle',
padding: [5, 6], // 增加标签内边距
},
labelLine: {
show: false,
length: 30,
smooth: true,
lineStyle: {
width: 1,
color: '#ffffff',
opacity: 1,
type: 'solid',
},
},
itemStyle: {
show: false,
borderColor: '#fff',
borderWidth: 1,
},
emphasis: {
label: {
fontSize: 20,
},
},
data: [],
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
watch(
() => props.size,
() => {
resize();
},
{
immediate: true,
}
);
watch(
() => props.activeIndex,
(newVal) => {
showLabel(newVal);
}
);
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
option.series[0].data = props.chartData;
setOptions(option);
showLabel(props.activeIndex);
}
// 动态生成带label状态的option
function getOption(activeIndex) {
// 浅拷贝数据(保留原始引用关系)
let myData = props.chartData.map((item, idx) => ({
...item,
label: {
show: idx === activeIndex, // 只显示当前选中层级的标签
},
labelLine: {
show: idx === activeIndex, // 只显示当前选中层级的引导线
},
}));
let myOption = {
...option,
series: [
{
...option.series[0],
data: myData,
},
],
};
return myOption;
}
// 切换显示层级
function showLabel(activeIndex) {
const newOption = getOption(activeIndex);
setOptions(newOption);
}
function onClick(params) {
emit('click', params);
}
return { chartRef };
},
};
</script>