# 全局 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. 单元测试和浏览器验证通过。