Repository navigation
Improve zoom and touchscreen experience by introducing continuous exponential scaling - #1375
Closed
Unnamed2964 wants to merge 7 commits into
Closed
Unnamed2964 wants to merge 7 commits into
Unnamed2964 wants to merge 7 commits into
Conversation
Replace the fixed ±10 step zoom with continuous multiplicative zoom: - Wheel: Math.pow(ZOOM_BASE, delta / sensitivity), where sensitivity is lower for touchpad pinch (ctrlKey) than for mouse wheel. - Pinch: distance ratio between consecutive touch frames. Add liveZoomRef / liveMinRef so consecutive wheel/pinch events within the same React batch read updated values instead of the stale Redux snapshot captured at the start of the render. Extract magic numbers to named constants in canvas.ts: ZOOM_BASE, ZOOM_MIN, ZOOM_MAX, WHEEL_SENSITIVITY, TOUCHPAD_SENSITIVITY, DELTA_LINE_MULTIPLIER (40, CSS spec 1 line ≈ 40px), DELTA_PAGE_MULTIPLIER.
Wrap node placement (station/misc-node) in a deferred callback (TOUCH_PLACE_DEFER_MS = 150ms) on touch devices so a quick second finger for pinch-to-zoom can cancel the destructive action. Similarly defer radial menu detection (TOUCH_RADIAL_DEFER_MS = 80ms). Track active pointer count (pointerCountRef) to detect multi-touch transitions in the PointerEvent layer. When a second finger arrives: - Cancel pending deferred node placement - Stop background drag and commit the current visual position via lastDragViewBoxMinRef instead of reverting to the pre-drag Redux state - Skip drag updates while multi-touch is active Add singleTouchTimerRef in touch-overlay to defer nearby-element lookup so pinch gestures skip it entirely.
Add soft-clamp near ZOOM_MIN / ZOOM_MAX (ZOOM_DAMPING_RANGE = 30): the zoom factor is progressively reduced as the zoom level approaches a boundary, giving the user a deceleration feel instead of an abrupt stop. Applied to both wheel zoom and pinch zoom. Re-initiate background drag when a single touch finger remains after a pinch ends: detect pointerType === 'touch' with pointerCountRef === 1 and active === undefined, then restart the drag from the current pointer position. The active === undefined guard prevents duplicate dispatches across batched React renders. Add a safety guard in handleTouchMove to clear singleTouchTimerRef if it is somehow still pending when multi-touch begins.
…vas jump When a touch drag-to-pinch transition happens before any RAF fires, lastDragViewBoxMinRef still holds a stale value from a previous drag session. The multi-touch cancellation then commits that stale position, causing the canvas to visibly jump. Initialize lastDragViewBoxMinRef to the current svgViewBoxMin both when a new drag begins (handleBackgroundDown) and when drag re-initiates after a pinch ends (handleBackgroundMove), so the committed position is always up-to-date.
Contributor
Author
|
现在对于触摸屏还是有问题:如果其中一根手指从对象开始,那么会漂移。 |
When multi-touch starts, handleTouchStart unconditionally dispatched setActive(undefined), which cleared a node's active state before the background's pointerdown guard could check it. This defeated the node-touch guard added in the previous commit, causing canvas drift when a finger started on a node and a second finger touched the background. Only clear active when no node is being interacted with (!active || active === 'background').
Contributor
Author
|
已修复 |
Contributor
Author
|
修改后的体验改变不太好用视频演示,需要麻烦在本地运行一下 |
Contributor
Author
|
现在有个合并冲突,我有空解决一下 |
Member
|
我们先开个议题跟踪吧,差点忘了还有这个合并请求 :( |
Contributor
Author
|
我打算明天重新review一遍本pr的修改代码,以防万一 更新:烦请再等一天 |
Contributor
Author
让我想想该怎么写... |
Contributor
Author
|
抱歉,需要些时间,但是我会在合理的时间内给出结果 |
Unnamed2964
marked this pull request as draft
March 24, 2026 22:20
Contributor
Author
|
感觉当时想的还不是很清楚,关闭这个pr了 |
Contributor
Author
|
短期内似乎不太可能继续推进,先关闭。相关说明见 railmapgen/rmg#789。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
描述
基于
fix/touchpad-zoom(阻止浏览器默认缩放),将画布缩放体验从固定步进升级为连续指数缩放,以获得和其他常用软件类似的缩放体验,并修复触屏设备上的多指手势冲突问题。目标是让鼠标滚轮、触控板捏合、手机双指捏合三种输入方式都获得丝滑、一致的缩放手感,同时消除触屏上误放置车站、视口闪回等 UX 问题。
主要更改
1. 连续指数缩放 (
5786ba12)currentZoom × ZOOM_BASE^(delta / sensitivity)的连续乘法公式,在任意缩放级别下手感一致ctrlKey)与鼠标滚轮使用不同灵敏度参数,适配两种设备的 deltaY 量级差异DOM_DELTA_LINE/DOM_DELTA_PAGEdeltaMode,统一为像素等价值liveZoomRef/liveMinRef,在同一帧内多次触发的滚轮事件之间保持缩放值同步,避免 React 批量更新导致中间缩放量丢失newDist / oldDist)乘法方式ZOOM_BASE、ZOOM_MIN、ZOOM_MAX、WHEEL_SENSITIVITY、TOUCHPAD_SENSITIVITY等)2. 触屏延迟放置与多指过渡 (
ccada3f1)TOUCH_PLACE_DEFER_MS),第二根手指按下时取消放置,防止捏合时误创建节点TOUCH_RADIAL_DEFER_MS),同理防止捏合误触pointerCountRef追踪活跃指针数量,第二根手指按下时中断背景拖拽并通过lastDragViewBoxMinRef提交当前视觉位置,防止视口闪回到拖拽前的状态3. 缩放阻尼与单指重新接管 (
46872f7b)ZOOM_MIN/ZOOM_MAX边界时(ZOOM_DAMPING_RANGE = 30),逐渐压缩缩放因子产生减速感,替代原来的硬截断handleTouchMove中添加安全兜底,防止多指触摸时定时器泄露其他说明
本功能代码主要由 Claude Sonnet 4.6/Opus 4.6 辅助生成。经过人工测试,确认功能行为符合预期且与现有业务逻辑兼容。