# Bug：Mask QC 画笔拖动与滚动条冲突，滚动位置漂移

## 问题描述

Mask QC 绘图时，画笔拖动与侧边滚动条发生冲突，滚动位置会跳回或漂移；此前叠加 `touch-action:none`、`overflow-anchor:none` 等 CSS 限制后仍未解决。

## 根因（已从当前 `index(9).html` 确认）

1. `pointerdown` 调用 `lockCanvasScroll()`，记录右侧 `.detail.scrollTop` 和 `window.scrollX/Y`。
2. 每次画笔拖动触发 `pointermove` 时，都调用 `restoreCanvasScroll()`，强制把滚动位置恢复到按下鼠标时的快照；其中还会反复执行 `window.scrollTo()`。
3. 画布指针捕获、绘图状态和滚动快照耦合，导致绘图期间滚动位置被强行回滚。
4. 原布局使用 `height/min-height: calc(100vh - 67px)`，假设顶部工具栏始终为 67px；工具栏换行或展开目录设置后，页面高度计算可能产生额外溢出。

## 修复方案（本地修复版已完成）

- 完全移除 `canvasScrollSnapshot`、`lockCanvasScroll()`、`restoreCanvasScroll()`，绘图事件不再写入或回滚任何滚动容器的位置。
- 引入 `activePointerId`，只允许当前主指针驱动笔画；其他指针不会结束或污染当前笔画。
- 将活动指针的移动、抬起、取消监听放在 window 层，配合 canvas pointer capture，指针移出画布后笔画仍能连续处理；捕获不可用时仍可由 window 事件维持操作。
- 窗口失焦或页面隐藏时清理活动指针状态，避免拖动状态卡住。
- 页面改为基于实际视口高度的 flex 布局；桌面端由左右面板独立滚动，平板/手机由应用容器滚动，不再依赖固定的 67px 顶栏高度。
- `server(6).py` 不需要修改：本次故障在前端指针/滚动控制层，服务端接口不参与滚动事件。

## 回归测试

使用 Chromium + Playwright，以 800×600 测试图片和本地 API 模拟响应，对真实页面 DOM、Pointer Events 和滚动容器执行交互测试：

- [x] 复现旧版问题：右侧滚动位置先设为 80，拖动画笔期间改为 150，旧版 pointermove 会将其重置为 80。
- [x] 修复版同一操作保持在 150，画笔像素写入成功（目标像素 alpha=255）。
- [x] 画笔结束后活动指针释放，绘图状态归零。
- [x] 空格 + 拖动只平移画布，画笔计数不增加。
- [x] 右侧面板滚轮正常滚动，画布缩放值不变。
- [x] 手机布局可在应用容器内滚动（scrollHeight 2840 / clientHeight 777）。
- [x] 平板布局可在应用容器内滚动（scrollHeight 2418 / clientHeight 733）。
- [x] 展开目录设置后，应用区域自动收缩；页面 body 未产生额外滚动（clientHeight 与 scrollHeight 均为 700）。
- [x] JavaScript `node --check` 通过；Python 服务端 `py_compile` 通过；自动化页面无 JavaScript 异常。

> 测试限制：无头 Chromium 使用覆盖式滚动条，因此未能模拟 Windows 系统可见滚动条滑块的物理拖动；需要在 Windows Chrome/Edge 上做最后的人工验收。

## 验收标准

1. 按住左键连续涂白、擦黑，笔迹不丢失、不跳点。
2. 绘图时不再自动修改右侧面板或页面滚动位置。
3. 直接拖动侧边滚动条时不得误触发画笔。
4. 空格拖动画布与画笔绘制互不串扰。
5. 桌面、平板、手机布局均无整页意外漂移。

本次本地修复文件：`index(9)_画笔滚动冲突彻底修复.html`。该文件已完成上述自动化交互测试；尚未提交到仓库实际页面文件。
