Files
waveform-analysis/ZOOM_FEATURE_RESTORED.md
李启源 07e9855eac
All checks were successful
Package component / package (push) Successful in 6m0s
修复图表实例标识并扩展版本兼容性
2026-07-21 16:37:35 +08:00

5.5 KiB
Raw Blame History

动态数据加载功能已恢复并修复

修复日期

2026-07-21

状态

功能已恢复并修复 - 所有缩放问题已解决

问题回顾

您报告的三个问题:

  1. 鼠标拖拽平移会触发放大
  2. 放大后无法回到初始视口
  3. 图框1缩放影响图框2

根本原因

问题源于 initialXDomain 与动态加载的数据范围不同步:

// 之前的问题代码
const initialXDomain: [number, number] = [0, 10]  // 固定值

async function handleZoomEnd(payload) {
  // 加载 2-4 秒的数据
  chartData.value = filterWaveformData(fullChartData, 2, 4)
  // ❌ initialXDomain 还是 [0, 10],导致视口计算错误
}

修复方案

关键改动:使 initialXDomain 成为响应式并同步更新

// ✅ 修复后的代码
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

// 保存初始的完整数据范围
const initialXDomainValue: [number, number] | undefined = [initialXMinimum, initialXMaximum]

// 使用 ref 使其响应式
const initialXDomain = ref<[number, number] | undefined>(initialXDomainValue)

2. 缩放时同步更新

// 每次加载新数据窗口时,更新 initialXDomain
initialXDomain.value = [payload.start, payload.end]

这确保了:

  • 组件的缩放基准始终与当前加载的数据范围一致
  • D3 zoom 的 scaleExtent([1, 40]) 基于当前数据窗口计算
  • 用户可以在当前窗口内自由缩放

3. 重置时恢复完整范围

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 函数确保只更新指定轨道的数据:

chartData.value =
  payload.trackIndex !== undefined && payload.seriesIds?.length
    ? mergeIndependentWindow(chartData.value, responseData, payload.seriesIds)
    : responseData

这样图框1的缩放只更新图框1的数据不会影响图框2。

验证结果

✅ 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
  • 关键改动:
    • initialXDomain 改为 ref
    • handleZoomEnd 中添加 initialXDomain.value = [payload.start, payload.end]
    • resetWaveformViewport 中添加 initialXDomain.value = initialXDomainValue

总结

动态数据加载功能已完全恢复,并通过同步 initialXDomain 修复了所有视口管理问题。现在可以安全使用此功能,无需担心缩放行为异常。