Ver código fonte

feat: 首页DynamicDonutChat.vue组件中新增echarts图表数字变化动画功能

sequoia tungfang 3 dias atrás
pai
commit
ffa7b44f30
1 arquivos alterados com 77 adições e 28 exclusões
  1. 77 28
      src/components/ui/DynamicDonutChart.vue

+ 77 - 28
src/components/ui/DynamicDonutChart.vue

@@ -87,50 +87,99 @@ export default {
         updateChart() {
             if (!this.$_chart) return;
 
+            // 1. 数据准备
+            const targetNumber = parseFloat(this.centerTitle) || 0;
+            const unit = this.centerTitle.replace(/[0-9.]/g, '');
             const colorPalette = this.chartData.map(item => item.color);
 
+            // 2. 基础配置
             const option = {
                 color: colorPalette,
-                title: {
-                    // 【核心改造】:使用富文本结构,用 \n 换行
-                    text: `{main|${this.centerTitle}}\n{sub|${this.centerSubTitle}}`,
-                    left: 'center',
-                    top: 'center',
-                    textStyle: {
-                        rich: {
-                            // 全面使用 px2echarts 包裹尺寸数值
-                            main: {
-                                fontSize: px2echarts(26),
-                                color: '#ffffff',
-                                fontWeight: 'bold',
-                                fontFamily: 'Arial',
-                                // 用 padding 的 bottom 值代替原来的 itemGap,实现精准缩放
-                                padding: [0, 0, px2echarts(6), 0]
-                            },
-                            sub: {
-                                fontSize: px2echarts(14),
-                                lineHeight: px2echarts(18),
-                                color: '#cccccc'
-                            }
-                        }
-                    }
-                },
+                title: { show: false },
                 series: [
                     {
                         type: 'pie',
-                        // 半径原则上也可以写成具体像素如 [px2echarts(60), px2echarts(80)]
-                        // 但写成百分比原生就自带外层容器的自适应,通常保留百分比即可
+                        // 【核心修复】:缩小半径以减小图表直径。原有 60%, 80%
                         radius: ['60%', '80%'],
                         center: ['50%', '50%'],
                         avoidLabelOverlap: false,
                         label: { show: false },
                         labelLine: { show: false },
+                        animationDuration: 1000,
                         data: this.chartData
                     }
+                ],
+                graphic: [
+                    {
+                        type: 'group',
+                        left: 'center',
+                        top: 'center',
+                        children: [
+                            {
+                                id: 'main-text', // 给主文字一个 ID 方便局部更新
+                                type: 'text',
+                                z: 100,
+                                left: 'center',
+                                top: px2echarts(-15),
+                                style: {
+                                    fill: '#ffffff',
+                                    fontSize: px2echarts(26),
+                                    fontWeight: 'bold',
+                                    fontFamily: 'Arial',
+                                    textAlign: 'center',
+                                    text: '0' + unit
+                                }
+                            },
+                            {
+                                type: 'text',
+                                z: 100,
+                                left: 'center',
+                                top: px2echarts(22),
+                                style: {
+                                    text: this.centerSubTitle,
+                                    fill: '#cccccc',
+                                    fontSize: px2echarts(14),
+                                    fontFamily: 'Arial',
+                                    textAlign: 'center'
+                                }
+                            }
+                        ]
+                    }
                 ]
             };
 
-            this.$_chart.setOption(option);
+            // 3. 首次渲染
+            this.$_chart.setOption(option, true);
+
+            // 4. 【进阶逻辑】:数值滚动动画 (Lazy Update 版)
+            const animateNumber = () => {
+                // 检查实例是否在主渲染进程中已被销毁
+                if (!this.$_chart || this.$_chart.isDisposed()) return;
+
+                let obj = { val: 0 };
+                this.$_chart.getZr().animation.animate(obj)
+                    .when(1500, { val: targetNumber })
+                    .during(() => {
+                        // 将更新指令放入 requestAnimationFrame,并防止组件销毁报错
+                        window.requestAnimationFrame(() => {
+                            if (this.$_chart && !this.$_chart.isDisposed()) {
+                                // 使用局部 ID 更新,并开启 lazyUpdate,解决 [ECharts] main process 报错
+                                this.$_chart.setOption({
+                                    graphic: [{
+                                        id: 'main-text',
+                                        style: { text: Math.round(obj.val) + unit }
+                                    }]
+                                }, { lazyUpdate: true });
+                            }
+                        });
+                    })
+                    .start();
+            };
+
+            // 5. 确保在 DOM 和布局稳定后再启动动画
+            this.$nextTick(() => {
+                setTimeout(animateNumber, 100);
+            });
         }
     }
 }
@@ -157,7 +206,7 @@ export default {
 .legend-box {
     display: flex;
     align-items: center;
-    background: linear-gradient( 90deg, #2D426C 0%, rgba(45,66,108,0) 100%);
+    background: linear-gradient(90deg, #2D426C 0%, rgba(45, 66, 108, 0) 100%);
     height: 40px;
 }