# 数据中心 · 历史记录 · 曲线趋势图改造方案 ## 1. 背景与问题 ### 1.1 业务场景 路径:**数据中心 → 历史记录**([`history.vue`](../src/views/dataCenter/history.vue))。 页面含三个 Tab:**设备**、**网关设备**、**场景**,各自有「曲线趋势图」或网关下的计算量 / 多设备对比 / 单子设备折线图。 ### 1.2 原始痛点 | 问题 | 说明 | |------|------| | 多曲线「压成直线」 | 多物模型量级差异大(如位移 168、角度 3、电压 12),共用单 Y 轴时范围被拉大,小幅波动在图上不可见。 | | 多 Y 轴布局异常 | 为每条曲线建隐藏 Y 轴时,ECharts 会为多轴计算偏移,曲线一多时绘图区被挤到一侧。 | | 图例占用空间 | 网关多设备对比图例项极多,默认换行占满高度,挤压 grid。 | | X 轴可读性 | 时间点密集时标签重叠。 | | 垂直空间不足 | 固定 480px 高度时,几十条归一化曲线仍显拥挤。 | --- ## 2. 总体思路 1. **独立 Y 轴模式**:不再使用「每 series 一个 Y 轴」,改为 **按每条曲线自身 min-max 归一化到 [-100, 100]**,**共用一条数值 Y 轴**,避免多轴布局副作用;**Tooltip 始终展示原始值**。 2. **共享 Y 轴模式**:保留原逻辑,单 Y 轴 + `scale: true`,便于对比绝对量级。 3. **归一化坐标展示**:独立模式下 Y 轴可见,刻度约 -100%~100%,并附说明性网格线。 4. **网关图**:图例与 grid 与设备 Tab 对齐策略;X 轴旋转 + 对齐刻度;必要时配合底部留白与 dataZoom。 5. **动态高度**:按 **series 数量** 增加图表容器高度(有上下限),并在 DOM 更新后 `resize`。 --- ## 3. 功能开关 - **数据字段**:`independentYAxis`(默认 `true`)。 - **UI**:设备 / 网关 / 场景三个图表卡片头部 **「独立Y轴 | 共享Y轴」** 开关。 - **切换行为**:`handleYAxisModeChange` 在 `$nextTick` 内按当前 Tab 与已有数据调用对应 `draw*Line`,无需重新请求接口。 --- ## 4. 核心实现 ### 4.1 归一化(独立模式) **方法**:`applyIndependentScale(series)` - 对每条 `series.data` 中可解析为数字的点,取该 series 全体有效点的 `min`、`max`。 - 映射公式:`value = ((num - min) / (max - min)) * 200 - 100`,落在 **[-100, 100]**。 - **常量序列**(`max === min`):映射为 **0**(中间水平线)。 - 每个数据点存为 `{ value, _original }`,`_original` 为归一化前的原始值(兼容负数与非数字展示)。 **返回的 Y 轴配置**(单轴): - `min: -100`, `max: 100` - `axisLine` / `axisTick` 显示 - `axisLabel.formatter`: 显示为 `xx%`(表示相对本曲线量程的位置,非物理单位) - `splitLine`:虚线网格,便于读趋势 ### 4.2 Tooltip **方法**:`independentScaleTooltip()` - `trigger: 'axis'` - `formatter`:时间轴标签 + 各 series **原始值**(从 `p.data._original` 读取) ### 4.3 共享模式 - `yAxis`: `{ type: 'value', scale: true }` - `tooltip`: `{ trigger: 'axis' }`(默认) ### 4.4 涉及的绘图方法 | 方法 | Tab / 场景 | |------|------------| | `drawDevLine` | 设备 | | `drawGwCalcLine` | 网关 · 计算量 | | `drawGwSingleLine` | 网关 · 单子设备 | | `drawSubCompareLine` | 网关 · 多设备同一变量对比 | | `drawSceneLine` | 场景 | 以上方法在 `independentYAxis === true` 时均走 `applyIndependentScale` + `independentScaleTooltip`。 ### 4.5 网关图布局要点 - `legend`: `align: 'right'`, `left: '3%'`, `top: '3%'`(与多行图例协调) - `grid.top: '30%'`,为图例留出区域,避免与曲线重叠 - `xAxis`: `boundaryGap: true`, `axisTick.alignWithLabel: true`, `axisLabel.rotate: 30` - `dataZoom`: `inside` + 滑块,便于时间范围缩放 - `toolbox`: 数据视图、还原、保存图片(与设备 Tab 能力对齐) ### 4.6 动态图表高度 **数据字段**(像素): - `devChartHeight`, `gwCalcChartHeight`, `gwSingleChartHeight`, `subCompareChartHeight`, `sceneChartHeight`(默认 480) **方法**:`calcChartHeight(seriesCount)` ```text height = clamp(480, seriesCount * 14 + 360, 1200) ``` 即:最少 480px,随曲线数量增加,**最多 1200px**。 **模板**:各图表容器使用 `:style="{ height: xxxChartHeight + 'px', ... }"`。 **绘制流程**: 1. 先算好 `series` 与 `series.length`,赋值对应 `xxxChartHeight` 2. `this.$nextTick(() => { init/clear → setOption → chart.resize() })` 保证先根据新高度更新 DOM,再初始化/重绘 ECharts。 --- ## 5. 数据流(简图) ```mermaid flowchart LR subgraph input [数据] API[历史接口] end subgraph mode [模式] IND[独立Y轴] SHR[共享Y轴] end subgraph render [渲染] NORM[逐条 min-max 到 -100~100] ONEAXIS[单 Y 轴] TT[Tooltip 原始值] end API --> IND API --> SHR IND --> NORM --> ONEAXIS ONEAXIS --> TT SHR --> ONEAXIS ``` --- ## 6. 使用说明(给产品/测试) 1. **独立 Y 轴(推荐多曲线看趋势)**:纵轴为各曲线**自身量程内的相对位置**(-100%~100%),对比不同物理量时看形状;**真实数值以 Tooltip 与下方表格为准**。 2. **共享 Y 轴**:纵轴为**真实数值**,适合量级接近、需比大小的变量;量级差很大时仍可能出现「看起来像直线」。 3. **曲线很多时**:图会自动变高(上限约 1200px),页面可纵向滚动查看全图。 --- ## 7. 相关文件 | 文件 | 说明 | |------|------| | [`yack-web/src/views/dataCenter/history.vue`](../src/views/dataCenter/history.vue) | 全部图表逻辑、开关、高度、归一化 | | [`yack-web/src/api/data/center.js`](../src/api/data/center.js) | 历史数据接口(未因本方案变更协议) | --- ## 8. 版本与维护建议 - 若需调整「多高算够」,改 `calcChartHeight` 中的系数 `14`、基础 `360`、上下限 `480`/`1200` 即可。 - 若产品要求 Y 轴显示「归一化」文案而非 `%`,可在 `applyIndependentScale` 返回的 `axisLabel` 中改为固定文案或 `name`/`nameLocation`。 - 新增同类折线图时,复用:`applyIndependentScale` / `independentScaleTooltip` / `calcChartHeight` + `$nextTick` + `resize` 模式。 --- *文档对应实现:历史记录页曲线趋势图(多 Tab、独立/共享 Y 轴、归一化 -100~100、动态高度)。*