|
|
@@ -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;
|
|
|
}
|
|
|
|