|
@@ -1,13 +1,39 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="tick-donut-wrapper">
|
|
<div class="tick-donut-wrapper">
|
|
|
<div class="custom-legend">
|
|
<div class="custom-legend">
|
|
|
- <div class="legend-item" v-for="(item, index) in chartData" :key="index">
|
|
|
|
|
- <span class="color-dot" :style="{ backgroundColor: item.color }"></span>
|
|
|
|
|
- <span class="legend-name" :title="item.name">{{ truncateName(item.name) }}</span>
|
|
|
|
|
- <span class="legend-value" v-if="item.value !== undefined && item.value !== null" :style="{ color: item.color }">
|
|
|
|
|
- {{ item.value }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <!-- 数据 ≤ legendLimit 直接列出, 不引入滚动开销; > legendLimit 走无缝滚动 + hover 停 -->
|
|
|
|
|
+ <SeamlessScroll
|
|
|
|
|
+ v-if="chartData.length > legendLimit"
|
|
|
|
|
+ :data="chartData"
|
|
|
|
|
+ :limit="legendLimit"
|
|
|
|
|
+ :speed="0.3"
|
|
|
|
|
+ measureSelector=".legend-rows"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #default="{ list }">
|
|
|
|
|
+ <div class="legend-rows">
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="legend-item"
|
|
|
|
|
+ v-for="(item, index) in list"
|
|
|
|
|
+ :key="(item._clone_id || 'orig') + '_' + (item._originalIndex !== undefined ? item._originalIndex : index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="color-dot" :style="{ backgroundColor: item.color }"></span>
|
|
|
|
|
+ <span class="legend-name" :title="item.name">{{ truncateName(item.name) }}</span>
|
|
|
|
|
+ <span class="legend-value" v-if="item.value !== undefined && item.value !== null" :style="{ color: item.color }">
|
|
|
|
|
+ {{ item.value }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </SeamlessScroll>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <div class="legend-item" v-for="(item, index) in chartData" :key="index">
|
|
|
|
|
+ <span class="color-dot" :style="{ backgroundColor: item.color }"></span>
|
|
|
|
|
+ <span class="legend-name" :title="item.name">{{ truncateName(item.name) }}</span>
|
|
|
|
|
+ <span class="legend-value" v-if="item.value !== undefined && item.value !== null" :style="{ color: item.color }">
|
|
|
|
|
+ {{ item.value }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="echarts-container" ref="chartRef"></div>
|
|
<div class="echarts-container" ref="chartRef"></div>
|
|
@@ -18,10 +44,12 @@
|
|
|
import * as echarts from 'echarts';
|
|
import * as echarts from 'echarts';
|
|
|
// 引入你项目的自适应 Mixin 和 px转换工具
|
|
// 引入你项目的自适应 Mixin 和 px转换工具
|
|
|
import echartsResize, { px2echarts } from '@/mixins/echartsResize.js';
|
|
import echartsResize, { px2echarts } from '@/mixins/echartsResize.js';
|
|
|
|
|
+import SeamlessScroll from '@/components/ui/SeamlessScroll.vue';
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'TickDonutChart',
|
|
name: 'TickDonutChart',
|
|
|
mixins: [echartsResize],
|
|
mixins: [echartsResize],
|
|
|
|
|
+ components: { SeamlessScroll },
|
|
|
props: {
|
|
props: {
|
|
|
// 传入的图表数据,格式如:[{ name: '定周期控制', value: 400, color: '#33ccff' }, ...]
|
|
// 传入的图表数据,格式如:[{ name: '定周期控制', value: 400, color: '#33ccff' }, ...]
|
|
|
chartData: {
|
|
chartData: {
|
|
@@ -37,6 +65,11 @@ export default {
|
|
|
centerSubTitle: {
|
|
centerSubTitle: {
|
|
|
type: String,
|
|
type: String,
|
|
|
default: ''
|
|
default: ''
|
|
|
|
|
+ },
|
|
|
|
|
+ // 左侧图例最多展示多少行 (超过此数自动滚动, 鼠标 hover 暂停)
|
|
|
|
|
+ legendLimit: {
|
|
|
|
|
+ type: Number,
|
|
|
|
|
+ default: 8
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
watch: {
|
|
watch: {
|
|
@@ -174,6 +207,18 @@ export default {
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
width: 45%; /* 图例区占据左侧 45% */
|
|
width: 45%; /* 图例区占据左侧 45% */
|
|
|
gap: 2px;
|
|
gap: 2px;
|
|
|
|
|
+ /* 最多 8 行: 每行 line-height 18px + 7 个 gap 2px = 158px
|
|
|
|
|
+ - ≤ 8 条: 内容自然居中, 不会撑爆
|
|
|
|
|
+ - > 8 条: SeamlessScroll 限定在这 158px 内自动滚动, hover 暂停 */
|
|
|
|
|
+ max-height: 158px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* SeamlessScroll 内部承载多份克隆数据的行容器, measureSelector=".legend-rows" */
|
|
|
|
|
+.legend-rows {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 2px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.legend-item {
|
|
.legend-item {
|