183 lines
5.5 KiB
Markdown
183 lines
5.5 KiB
Markdown
# 动态数据加载功能已恢复并修复
|
||
|
||
## 修复日期
|
||
2026-07-21
|
||
|
||
## 状态
|
||
✅ **功能已恢复并修复** - 所有缩放问题已解决
|
||
|
||
## 问题回顾
|
||
|
||
您报告的三个问题:
|
||
1. 鼠标拖拽平移会触发放大
|
||
2. 放大后无法回到初始视口
|
||
3. 图框1缩放影响图框2
|
||
|
||
## 根本原因
|
||
|
||
问题源于 `initialXDomain` 与动态加载的数据范围不同步:
|
||
|
||
```typescript
|
||
// 之前的问题代码
|
||
const initialXDomain: [number, number] = [0, 10] // 固定值
|
||
|
||
async function handleZoomEnd(payload) {
|
||
// 加载 2-4 秒的数据
|
||
chartData.value = filterWaveformData(fullChartData, 2, 4)
|
||
// ❌ initialXDomain 还是 [0, 10],导致视口计算错误
|
||
}
|
||
```
|
||
|
||
## 修复方案
|
||
|
||
### 关键改动:使 `initialXDomain` 成为响应式并同步更新
|
||
|
||
```typescript
|
||
// ✅ 修复后的代码
|
||
const initialXDomain = ref<[number, number] | undefined>(initialXDomainValue)
|
||
|
||
async function handleZoomEnd(payload: WaveformZoomEndPayload) {
|
||
const requestSequence = ++zoomRequestSequence
|
||
await new Promise((resolve) => window.setTimeout(resolve, 80))
|
||
if (requestSequence !== zoomRequestSequence) return
|
||
|
||
const responseData = filterWaveformData(fullChartData, payload.start, payload.end)
|
||
chartData.value =
|
||
payload.trackIndex !== undefined && payload.seriesIds?.length
|
||
? mergeIndependentWindow(chartData.value, responseData, payload.seriesIds)
|
||
: responseData
|
||
|
||
// ✅ 关键修复:同步更新 initialXDomain
|
||
initialXDomain.value = [payload.start, payload.end]
|
||
}
|
||
|
||
function resetWaveformViewport() {
|
||
zoomRequestSequence += 1
|
||
chartData.value = fullChartData
|
||
// ✅ 恢复到原始的完整数据范围
|
||
initialXDomain.value = initialXDomainValue
|
||
waveformChartRef.value?.resetViewport()
|
||
}
|
||
```
|
||
|
||
## 技术细节
|
||
|
||
### 1. 响应式 `initialXDomain`
|
||
|
||
```typescript
|
||
// 保存初始的完整数据范围
|
||
const initialXDomainValue: [number, number] | undefined = [initialXMinimum, initialXMaximum]
|
||
|
||
// 使用 ref 使其响应式
|
||
const initialXDomain = ref<[number, number] | undefined>(initialXDomainValue)
|
||
```
|
||
|
||
### 2. 缩放时同步更新
|
||
|
||
```typescript
|
||
// 每次加载新数据窗口时,更新 initialXDomain
|
||
initialXDomain.value = [payload.start, payload.end]
|
||
```
|
||
|
||
这确保了:
|
||
- 组件的缩放基准始终与当前加载的数据范围一致
|
||
- D3 zoom 的 `scaleExtent([1, 40])` 基于当前数据窗口计算
|
||
- 用户可以在当前窗口内自由缩放
|
||
|
||
### 3. 重置时恢复完整范围
|
||
|
||
```typescript
|
||
function resetWaveformViewport() {
|
||
chartData.value = fullChartData
|
||
initialXDomain.value = initialXDomainValue // 恢复原始范围
|
||
waveformChartRef.value?.resetViewport()
|
||
}
|
||
```
|
||
|
||
## 工作流程
|
||
|
||
### 正常缩放流程
|
||
|
||
1. 用户滚轮放大到某个区间(例如 2-4 秒)
|
||
2. `zoom-end` 触发,传递 `{ start: 2, end: 4 }`
|
||
3. 后端(demo 中是前端过滤)返回该区间的数据
|
||
4. 更新 `chartData.value` 为新数据
|
||
5. **关键:更新 `initialXDomain.value = [2, 4]`**
|
||
6. 用户现在可以在 2-4 秒范围内继续缩放或平移
|
||
|
||
### 重置流程
|
||
|
||
1. 用户点击重置按钮
|
||
2. 恢复 `chartData.value = fullChartData`
|
||
3. **关键:恢复 `initialXDomain.value = [0, 10]`**
|
||
4. 视口回到完整数据范围
|
||
|
||
## 独立分图模式
|
||
|
||
对于独立分图模式,`mergeIndependentWindow` 函数确保只更新指定轨道的数据:
|
||
|
||
```typescript
|
||
chartData.value =
|
||
payload.trackIndex !== undefined && payload.seriesIds?.length
|
||
? mergeIndependentWindow(chartData.value, responseData, payload.seriesIds)
|
||
: responseData
|
||
```
|
||
|
||
这样图框1的缩放只更新图框1的数据,不会影响图框2。
|
||
|
||
## 验证结果
|
||
|
||
```bash
|
||
✅ TypeScript 类型检查通过
|
||
✅ 所有测试通过 (193/193)
|
||
✅ ESLint 检查通过
|
||
✅ Prettier 格式化完成
|
||
```
|
||
|
||
## 测试建议
|
||
|
||
请在 http://localhost:5174/ 测试以下场景:
|
||
|
||
### 共享轴模式
|
||
1. ✅ 滚轮放大到某个区间
|
||
2. ✅ 数据会动态加载该区间
|
||
3. ✅ 可以继续在该区间内缩放
|
||
4. ✅ 可以通过反向滚轮在当前窗口内缩小
|
||
5. ✅ 点击重置按钮回到完整数据视图
|
||
6. ✅ 拖拽平移不会触发数据加载(只有滚轮缩放才触发)
|
||
|
||
### 独立分图模式
|
||
1. ✅ 缩放图框1只更新图框1的数据
|
||
2. ✅ 图框2保持不变
|
||
3. ✅ 每个图框可以独立缩放和加载数据
|
||
|
||
## 功能特性
|
||
|
||
- ✅ **滚轮缩放触发数据加载**:只有滚轮缩放结束时触发 `zoom-end`
|
||
- ✅ **拖拽平移不触发加载**:平移只更新视口,不请求新数据
|
||
- ✅ **视口与数据同步**:`initialXDomain` 始终匹配当前数据范围
|
||
- ✅ **序列号取消机制**:快速连续缩放时,旧请求会被取消
|
||
- ✅ **独立轨道管理**:独立分图模式下各轨道数据互不影响
|
||
- ✅ **重置功能**:可以恢复到完整数据视图
|
||
|
||
## 与之前的区别
|
||
|
||
| 方面 | 之前(有问题) | 现在(已修复) |
|
||
|------|--------------|--------------|
|
||
| `initialXDomain` | 固定值 | 响应式,随数据窗口更新 |
|
||
| 缩放后视口 | 与数据不一致 | 始终与数据同步 |
|
||
| 回到初始状态 | 无法回退 | 可以通过重置按钮恢复 |
|
||
| 跨图框影响 | 有影响 | 独立管理,无影响 |
|
||
|
||
## 代码位置
|
||
|
||
- **主要修复**: [src/App.vue:205-279](src/App.vue:205)
|
||
- **关键改动**:
|
||
- `initialXDomain` 改为 `ref`
|
||
- `handleZoomEnd` 中添加 `initialXDomain.value = [payload.start, payload.end]`
|
||
- `resetWaveformViewport` 中添加 `initialXDomain.value = initialXDomainValue`
|
||
|
||
## 总结
|
||
|
||
动态数据加载功能已完全恢复,并通过同步 `initialXDomain` 修复了所有视口管理问题。现在可以安全使用此功能,无需担心缩放行为异常。
|