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.

307 lines
9.2 KiB

6 months ago
<template>
<div class="chart-container" ref="chartRef" style="width: 450px; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
props: {
// 合并后的数据结构
chartData: {
type: Object,
required: true,
default: () => ({
level1: [{ value: 100, name: '防御材料' }],
level2: [
{ value: 20, name: '袋类' },
{ value: 45, name: '土工布类' },
{ value: 25, name: '桩类' },
{ value: 10, name: '金属丝及其制品类' }
],
level3: [
{ value: 8, name: '个', parent: '袋类' },
{ value: 12, name: '只', parent: '袋类' },
{ value: 20, name: '捆', parent: '土工布类' },
{ value: 25, name: '匹', parent: '土工布类' },
{ value: 13, name: '根', parent: '桩类' },
{ value: 12, name: '堆', parent: '桩类' },
{ value: 2, name: '条', parent: '金属丝及其制品类' },
{ value: 4, name: '捆', parent: '金属丝及其制品类' },
{ value: 4, name: '个', parent: '金属丝及其制品类' }
]
})
}
},
data() {
return {
chart: null
}
},
methods: {
// 生成唯一的颜色
generateUniqueColors(count) {
const baseColors = [
{ start: '#319ae2', end: '#4F7CAC' }, // 深蓝 → 浅蓝
{ start: '#f57e4f', end: '#ebcc88' }, // 鲜黄橙 → 浅黄橙
{ start: '#705fbc', end: '#8d8cd6' }, // 深紫色 → 浅紫色
{ start: '#90f9bf', end: '#88ba91' } // 深青蓝 → 浅青蓝
];
const colors = [];
for (let i = 0; i < count; i++) {
colors.push(baseColors[i % baseColors.length]);
}
return colors;
// const colors = [];
// const baseColors = [
// '#003366', // 深蓝
// '#005577', // 深青蓝
// '#007799', // 深湖蓝
// '#8800cc', // 深紫
// '#cc0066', // 深玫红
// '#ff3366', // 鲜艳玫红
// '#ff6600', // 鲜橙
// '#ff9900', // 鲜黄橙
// '#009966', // 深绿
// '#006666', // 深青
// '#003399', // 深靛蓝
// '#660099', // 深紫罗兰
// '#990033', // 深酒红
// '#0066cc', // 深天蓝
// '#0099cc', // 鲜艳蓝绿
// '#333399' // 深蓝紫
// ];
// for (let i = 0; i < count; i++) {
// const startColor = baseColors[i % baseColors.length];
// const endColor = baseColors[(i + 4) % baseColors.length];
// colors.push({
// start: startColor,
// end: endColor
// });
// }
// return colors;
},
initChart() {
const chartDom = this.$refs.chartRef;
this.chart = echarts.init(chartDom);
// 核心配置:统一各层的起始角度、排列方向
const commonPieConfig = {
clockwise: false,
startAngle: 90,
avoidLabelOverlap: true
};
// 为第二层生成颜色
const level2Colors = {};
const colors = this.generateUniqueColors(this.chartData.level2.length);
this.chartData.level2.forEach((item, index) => {
level2Colors[item.name] = colors[index];
});
// 计算每个父级分类下的子项数量
const parentItemCounts = {};
this.chartData.level3.forEach(item => {
parentItemCounts[item.parent] = (parentItemCounts[item.parent] || 0) + 1;
});
// 为第三层数据分配颜色和角度
const level3DataWithColor = this.chartData.level3.map((item, index) => {
const colorConfig = level2Colors[item.parent] || { start: '#2bb8fc', end: '#93cbfd' };
const parentCount = parentItemCounts[item.parent];
const parentIndex = this.chartData.level2.findIndex(d => d.name === item.parent);
const parentAngle = 360 / this.chartData.level2.length;
const childAngle = parentAngle / parentCount;
const startAngle = 90 + (parentIndex * parentAngle);
const itemIndex = this.chartData.level3.filter(d => d.parent === item.parent).indexOf(item);
const itemStartAngle = startAngle + (itemIndex * childAngle);
return {
...item,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [{
offset: 0,
color: colorConfig.start
}, {
offset: 1,
color: colorConfig.end
}]
}
},
startAngle: itemStartAngle,
endAngle: itemStartAngle + childAngle
};
});
// 为第二层数据添加渐变效果
const level2DataWithGradient = this.chartData.level2.map((item) => {
const colorConfig = level2Colors[item.name];
return {
...item,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [{
offset: 0,
color: colorConfig.start
}, {
offset: 1,
color: colorConfig.end
}]
}
}
};
});
// 为第一层数据添加渐变效果
const level1DataWithGradient = this.chartData.level1.map(item => ({
...item,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [{
offset: 0,
color: '#2bb8fc',
}, {
offset: 1,
color: '#93cbfd'
}]
}
}
}));
const option = {
// title: {
// text: '防御材料多层环形分布',
// left: 'center',
// textStyle: { color: '#fff', fontSize: 16 }
// },
tooltip: {
trigger: 'item',
formatter: '{b} : {c} ({d}%)'
},
series: [
// 第三层(最底层)
{
...commonPieConfig,
type: 'pie',
z: 1,
radius: ['45%', '65%'],
label: {
show: true,
position: 'outside',
color: '#fff',
formatter: '{b}\n{d}%',
fontSize: 12
},
labelLine: {
show: true,
length: 10,
length2: 15,
lineStyle: { color: '#fff' }
},
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowOffsetX: 2,
shadowOffsetY: 2
},
data: level3DataWithColor
},
// 第二层(中间层)
{
...commonPieConfig,
type: 'pie',
z: 2,
radius: ['25%', '45%'],
label: {
show: true,
position: 'inside',
color: '#fff',
formatter: '{b}\n{c}',
fontSize: 13
},
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowOffsetX: 2,
shadowOffsetY: 2
},
data: level2DataWithGradient
},
// 第一层(最上层)
{
...commonPieConfig,
type: 'pie',
z: 3,
radius: ['0%', '25%'],
label: {
show: true,
position: 'inside',
color: '#fff',
formatter: '{b}\n{c}',
fontSize: 14
},
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowOffsetX: 2,
shadowOffsetY: 2
},
data: level1DataWithGradient
}
]
};
this.chart.setOption(option);
}
},
mounted() {
this.initChart();
// 响应式:窗口变化时重绘
window.addEventListener('resize', () => {
this.chart && this.chart.resize();
});
},
watch: {
chartData: {
handler() {
this.initChart();
},
deep: true
}
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
window.removeEventListener('resize', this.chart.resize);
}
}
</script>
<style scoped>
.chart-container {
background: transparent; /* 深色背景匹配设计图 */
padding: 20px;
}
</style>