This commit is contained in:
lcw
2025-11-22 21:59:58 +08:00
parent ea3022c3f6
commit 93c49dff27
661 changed files with 195357 additions and 2160 deletions

View File

@ -1,109 +1,169 @@
<template>
<div ref="chartRef" :style="{ width: '100%', height: '400px' }"></div>
<div ref="chartRef" :style="{ width: '100%', height: '100%' }"></div>
</template>
<script>
import { defineComponent, onMounted, ref } from 'vue'
<script setup>
import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
import 'echarts-gl'
export default defineComponent({
name: 'Pie3D',
setup() {
const chartRef = ref(null)
let chart = null
const initChart = () => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value)
const option = {
backgroundColor: '#1a213c',
tooltip: {
formatter: '{b}: {c} ({d}%)',
backgroundColor: 'rgba(0,0,0,0.7)',
borderColor: '#1a213c',
textStyle: {
color: '#fff'
}
},
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
textStyle: {
color: '#fff'
},
formatter: function(name) {
const data = option.series[0].data
const total = data.reduce((sum, item) => sum + item.value, 0)
const target = data.find(item => item.name === name)
const percentage = ((target.value / total) * 100).toFixed(0)
return `${name} ${target.value}`
}
},
series: [{
type: 'pie',
radius: ['30%', '55%'],
center: ['40%', '50%'],
roseType: false,
zlevel: 10,
startAngle: 35,
selectedMode: 'single',
selectedOffset: 10,
data: [
{ value: 18, name: '红色', itemStyle: { color: '#ff4d4f' } },
{ value: 13, name: '橙色', itemStyle: { color: '#ff7a45' } },
{ value: 17, name: '黄色', itemStyle: { color: '#ffc53d' } },
{ value: 2, name: '蓝色', itemStyle: { color: '#40a9ff' } }
],
label: {
show: true,
formatter: '{d}%',
color: '#fff',
position: 'outside',
fontSize: 14,
fontWeight: 'bold'
},
emphasis: {
focus: 'self',
scaleSize: 10,
itemStyle: {
shadowBlur: 20,
shadowOffsetX: 5,
shadowOffsetY: 5,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
borderRadius: 4,
borderColor: '#1a213c',
borderWidth: 2
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200;
}
}]
}
chart.setOption(option)
}
onMounted(() => {
initChart()
window.addEventListener('resize', () => {
chart && chart.resize()
})
})
return {
chartRef
}
const props = defineProps({
data: {
type: Array,
default: () => []
},
color: {
type: Array,
default:() => []
}
})
const chartRef = ref(null)
let chart = null
const initChart = () => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value)
const option = {
// backgroundColor: '#1a213c',
tooltip: {
formatter: '{b}: {c} ({d}%)',
backgroundColor: 'rgba(0,0,0,0.7)',
borderColor: '#1a213c',
textStyle: {
color: '#fff'
}
},
legend: {
orient: 'vertical',
right: '0%',
top: 'center',
textStyle: {
color: '#fff'
},
formatter: function (name) {
const data = option.series[0].data
const total = data.reduce((sum, item) => sum + item.value, 0)
const target = data.find(item => item.name === name)
const percentage = ((target.value / total) * 100).toFixed(0)
return `${name} ${target.value}`
}
},
series: [{
type: 'pie',
radius: ['30%', '55%'],
center: ['40%', '50%'],
roseType: false,
zlevel: 10,
startAngle: 35,
selectedMode: 'single',
selectedOffset: 10,
data:[...props.data],
label: {
show: true,
formatter: '{d}%',
color: '#fff',
position: 'outside',
fontSize: 14,
fontWeight: 'bold'
},
emphasis: {
focus: 'self',
scaleSize: 10,
itemStyle: {
shadowBlur: 20,
shadowOffsetX: 5,
shadowOffsetY: 5,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
borderRadius: 4,
borderColor: '#1a213c',
borderWidth: 2
},
// 启用全局动画控制器
animation: true,
// 关键设置animationDelayUpdate确保数据更新时也有动画
animationDelayUpdate: function (idx) {
return idx * 300;
},
// 逐个显示的动画效果 - 改为从透明到不透明的过渡效果
animationType: 'opacity',
animationEasing: 'cubicOut',
// 关键:设置初始样式,让每个扇形从透明状态开始
// 使用动画帧序列来控制动画过程
animation: true,
animationDuration: 1000,
animationDelay: function (idx) {
// 按照索引顺序依次显示,设置更明显的延迟
return idx * 400;
},
// 动画开始前的回调,确保动画效果
animationBegin: function() {
// 可以在这里进行额外的动画初始化
return 0;
},
// 动画帧序列,控制每个关键帧的样式
animationFrame: function (idx, percent) {
// percent参数是从0到1的动画进度
return {
opacity: percent,
scale: 0.8 + percent * 0.2 // 从0.8放大到1
};
}
}],
media: [
{
query: { minAspectRatio: 1 },
option: {
series: [
{ center: ['36%', '50%'] },
]
}
}
]
}
chart.setOption(option)
}
onMounted(() => {
initChart()
window.addEventListener('resize', () => {
chart && chart.resize()
})
})
// 监听数据变化,确保动画在数据更新时也能触发
watch(
() => props.data,
(newData) => {
if (chart && newData && newData.length > 0) {
// 使用clear方法强制重新渲染并触发动画
chart.clear()
initChart()
}
},
{ deep: true }
)
// 组件卸载时清理资源
const cleanup = () => {
if (chart) {
chart.dispose()
chart = null
}
window.removeEventListener('resize', () => {
chart && chart.resize()
})
}
// 组件卸载时执行清理
onUnmounted(() => {
cleanup()
})
</script>
<style scoped>
</style>
<style scoped></style>