This commit is contained in:
2026-07-12 21:26:08 +08:00
commit 9dd41afd48
502 changed files with 129901 additions and 0 deletions
@@ -0,0 +1,219 @@
# 全局 Sigma 图谱平滑缩放与左下缩放按钮设计
日期:2026-06-26
分支:`codex/fix-global-graph-zoom-controls`
关联:GitHub issue #73
## 背景
当前工作台图谱有两套视图:
- 全局视图使用 Sigma/Graphology。
- 社区视图使用现有 DOM 图谱相机。
用户反馈集中在全局视图:滚轮和触控板缩放太快,轻轻一滑就突然变大或变小;继续缩小还可能让节点小到几乎消失。社区视图的缩放手感相对舒服,原因是它按真实滚轮距离连续计算缩放,并且有缩放边界。
这次 issue #73 提供的是重要线索,不作为唯一方案来源。结合当前代码后,推荐方案是:工作台全局 Sigma 图谱继续支持滚轮/触控板缩放,但不再使用 Sigma 默认的“按事件方向跳档”的滚轮手感;改为项目自己的连续缩放逻辑,并新增左下独立的放大/缩小按钮。
## 目标
1. 全局图谱滚轮/触控板缩放变得平顺、可控,接近社区视图现有手感。
2. 全局图谱不再因为轻微滑动突然变很大或很小。
3. 全局图谱缩放有合理上下限,避免无限放大或无限缩小。
4. 全局图谱左下增加独立的 `+` / `-` 缩放按钮。
5. 滚轮、触控板、按钮使用同一套缩放规则,不出现三种不同手感。
## 不做
1. 不改离线 HTML 的完整体验;本次只保证共享代码改动不主动破坏离线入口。
2. 不改社区视图的缩放体验。
3. 不改图谱数据、选择、搜索、筛选、Pin、社区高亮、右抽屉等功能语义。
4. 不引入新的图谱库或新的 npm 依赖。
5. 不修改 `node_modules/`
## 用户体验定义
### 1. 滚轮和触控板仍然可以缩放
全局图谱保留滚轮/触控板缩放。改变的是缩放计算方式,不是取消滚轮缩放。
### 2. 缩放必须连续
触控板轻滑一点,只缩放一点;滑动距离更大,缩放幅度才更大。
当前 Sigma 默认滚轮逻辑主要看滚轮方向,一次事件就是固定倍率跳档。这个模型会让高频小 delta 的触控板变成连续猛跳。新设计要改为按真实 `deltaY` 计算缩放倍率。
参考社区视图现有逻辑:
- 先把 wheel delta 标准化为像素距离。
- 再用指数曲线把 delta 映射成缩放倍率。
- 单次缩放倍率做防甩动限制。
全局 Sigma 视图采用同一类规则:
```text
nextRatio = currentRatio * exp(normalizedDeltaY * WHEEL_ZOOM_SPEED)
```
说明:
- 社区视图的 `scale` 越大表示越放大。
- Sigma 的 `ratio` 越小表示越放大。
- 所以全局 Sigma 用 `exp(+deltaY * speed)`,与社区视图的 `scale * exp(-deltaY * speed)` 在手感方向上对应。
- `WHEEL_ZOOM_SPEED` 使用社区视图当前舒服的值:`0.0016`。只有浏览器实测证明全局 Sigma 与社区视图仍有明显偏差时,才允许带测试记录调整这个常量;不能回到按事件跳档。
### 3. 缩放必须稳定
滚轮/触控板缩放时,以鼠标所在点为缩放锚点。用户指着哪里缩放,哪里就尽量留在原地。
按钮缩放时,以当前画面中心为缩放锚点。点击 `+``-` 不应该让画面突然飞到别处。
### 4. 缩放必须有边界
全局 Sigma 相机要设置 `minCameraRatio``maxCameraRatio`,并且项目自己的缩放逻辑也要遵守同一边界。
边界目标:
- 最大放大:能看清局部节点,但不把节点放到失控巨大。
- 最大缩小:能退回全局关系,但不让节点小到消失。
实现初始值:
- 放大下限:`minCameraRatio = 0.3`
- 缩小上限:`maxCameraRatio = 3`
如果视觉验证发现这两个值仍然让节点过大或过小,必须用新的浏览器验证结果说明为什么调整,并同步更新测试预期。无验证记录时,不继续调参。
### 5. 滚轮缩放不能积压动画
滚轮/触控板缩放应该即时响应,不排队播放动画。用户停止滚动后,画面也应很快停下,不能继续追一串旧动画。
因此:
- 滚轮/触控板缩放直接更新相机状态。
- 按钮缩放可以有短动画,但下一次点击必须接管上一次动画目标。
### 6. 按钮步长要明确但不猛
左下缩放按钮是地图导航控件,不是精细触控板替代品。
按钮点击一次使用中等固定步长:
- `+`:放大一档,`ratio` 乘以 `1 / 1.18`
- `-`:缩小一档,`ratio` 乘以 `1.18`
这个步长比触控板轻滑更明确,但不能像当前全局滚轮那样猛跳。
## 交互布局
新增一个独立的左下缩放控件:
- 位置:全局图谱画布左下角。
- 内容:竖向排列 `+``-`
- 样式:沿用现有图谱工具条的半透明纸面风格,但作为单独控件存在。
- 与现有工具条关系:不放进顶部“筛选 / 图例 / 回全图”工具条。
- 与“回全图”关系:`+` / `-` 只缩放;“回全图”继续负责回到全局构图。
控件区域本身要阻止画布滚轮缩放和点击穿透,避免用户在按钮附近滚动时误操作图谱。
## 架构设计
### 1. 缩放控制归属
缩放控制放在共享图谱引擎的 Sigma 全局渲染路径中,而不是放在工作台 React 外壳里。
理由:
- 当前全局图谱相机由 `packages/graph-engine/src/render/sigma-global-renderer.ts` 管理。
- Sigma 的鼠标事件、相机状态、锚点缩放都在这一层更容易正确处理。
- 工作台外壳不应该理解 Sigma 相机细节。
### 2. Sigma 默认滚轮处理
Sigma 的 mouse captor 会先发出 `wheel` 事件,再执行默认缩放。项目应监听这个 `wheel` 事件并调用 `preventSigmaDefault()`,阻止 Sigma 默认跳档缩放,然后执行项目自己的连续缩放。
需要使用的 Sigma 能力:
- `getMouseCaptor().on("wheel", handler)`:接管滚轮事件。
- wheel payload 的 `original.deltaY` / `original.deltaMode`:读取真实滚轮输入。
- `getCamera().getState()`:读取当前相机。
- `getViewportZoomedState(pointer, nextRatio)`:按鼠标位置计算新相机状态。
- `getCamera().setState(nextState)`:即时更新滚轮缩放。
如果某个运行环境缺少上述能力,必须降级为保守的 Sigma 参数方案,而不是让全局缩放不可用。
### 3. 缩放按钮
`createGraphToolbar` 不承载缩放按钮。新增一个独立的 Sigma 缩放控件创建函数,挂载到 Sigma 全局 route shell 内。
控件通过 renderer 暴露的缩放方法驱动相机,例如:
- `zoomIn()`
- `zoomOut()`
按钮缩放使用当前 Sigma 容器中心点作为锚点,计算方式与滚轮一致,只是输入为固定倍率。
### 4. 与现有高亮相机动画的关系
当前 `main` 已经有全局社区高亮与轻微相机构图动画。缩放改动必须与它共存:
- 选中社区后仍允许现有轻微构图。
- 用户滚轮/按钮缩放后,以用户缩放后的相机为准。
- 滚轮缩放不触发社区选择或清空选择。
- “回全图”仍然可以回到全局构图。
## 错误与降级
1. 如果无法读取真实 wheel delta,使用 Sigma wheel payload 的 delta 做保守计算,但仍要避免默认 `1.7` 跳档。
2. 如果无法使用 `getViewportZoomedState`,按钮和滚轮都不应让画面飞走;可以退化为以当前相机中心缩放。
3. 如果 Sigma runtime 不支持 mouse captor,则至少设置较温和的 `zoomingRatio` 与相机上下限,保证不出现无限缩放。
4. 所有异常通过现有 `onFatalError` 路径上报,不让整张图谱黑屏。
## 测试计划
### 单元测试
1. `sigma-global-renderer.test.ts`
- 创建 Sigma 时包含合理的相机边界。
- wheel handler 会阻止 Sigma 默认缩放。
-`deltaY` 只产生小幅缩放,大 `deltaY` 产生更明显缩放。
- 连续 wheel 不排队动画,使用即时相机更新。
- wheel 缩放使用鼠标位置作为锚点。
- `zoomIn` / `zoomOut` 使用同一套缩放计算与相机边界。
2. `renderer-boundary.test.ts`
- 左下缩放控件存在。
- `+` / `-` 点击分别触发放大/缩小回调。
- 控件点击不穿透到图谱选择。
3. `gestures.test.ts` 或等价覆盖
- 滚轮经过缩放控件时不触发图谱缩放。
### 浏览器验证
1. 启动工作台,进入全局图谱。
2. 使用触控板轻滑:图谱只轻微缩放,不猛跳。
3. 连续滚动后松手:画面快速停止,不继续追动画。
4. 鼠标停在节点附近滚轮缩放:该区域保持稳定,不飞跑。
5. 多次缩小:节点仍可见,不能缩到消失。
6. 多次放大:节点不会失控巨大。
7. 点击左下 `+` / `-`:画面按中等步长缩放,且以画面中心为基准。
8. 选中社区后再缩放:高亮仍在,缩放正常。
9. 回全图仍按原语义工作。
### 回归检查
- `npm run test -w @llm-wiki/graph-engine`
- 受影响情况下运行 Sigma 全局浏览器验证脚本。
- 若改动 CSS 或控件布局,打开工作台实际查看浅色/深色下左下按钮是否清晰、不遮挡主要图谱内容。
## 完成标准
这个任务实现完成时,必须同时满足:
1. 工作台全局图谱滚轮/触控板缩放手感接近社区视图,不再轻滑猛跳。
2. 工作台全局图谱缩放有上下限,不会无限缩小或无限放大。
3. 工作台全局图谱左下有独立 `+` / `-` 缩放按钮。
4. 按钮和滚轮使用同一套缩放规则。
5. 现有全局社区高亮、搜索、筛选、Pin、回全图没有被破坏。
6. 单元测试和浏览器验证通过。