-
Notifications
You must be signed in to change notification settings - Fork 116
Description
问题描述
问题最早可追溯至 #347 ,当时我提出的问题大概是 “使用鼠标向下平移画布比向上平移快;shift+鼠标向右平移比向左平移快;ctrl+鼠标缩小比放大快”,没过多久又有其他人提出了类似 issue #383 。后来我在 #347 追问后官方给出了两个方案:
- 使用 custom 自定义窗口缩放逻辑
- 新增了
posDeltaSpeed
和negDeltaSpeed
两个配置项
不知道为什么我总感觉这不是最佳的解决方案
鼠标平移步幅不一致的完美解决
后来,有人通过查看源码,找到了通过鼠标平移步幅不一致的问题所在

原因是只对正 delta 值做了 50 的限制
官方看到 issue 后也在第一时间更新发布,非常感谢🙏🙏🙏。
鼠标缩放步幅不一致原因猜想
有了前人的经验,我也想通过查看源码的方式看能不能找到鼠标缩放步幅不一致的问题所在。
我看看能不能先把这个异常现象说的更通俗一些:
参考miro,假如画布上一个元素,鼠标向下滚动一次缩小一次画布,再向上滚动一次放大一次画布,这个时候元素看起来和之前是一样大的(画布的缩放值一缩一放回到了之前大小)。
我试着找找原因
1.鼠标问题。我是window11笔记本+外置鼠标,而不是笔记本自带触控板。可能因为现在鼠标灵敏度比较高,向下滚动一次deltaY值为333,向上滚动一次deltaY值-333

鼠标deltaY值太大,如果使用笔记本触控板,不会有这么大的deltaY。
(非根本原因,但会影响within)
2.代码限制。packages\viewport\src\interaction\WheelEventHelper.ts,getScale方法
getScale(event: IWheelEvent, config: IWheelConfig): number {
let zoom: boolean
let scale = 1
let { zoomMode, zoomSpeed } = config
const delta = event.deltaY || event.deltaX
if (zoomMode) {
// mac 触摸板滚动手势的deltaY是整数, 鼠标滚动/触摸板缩放的deltaY有小数点, firfox鼠标滚动为整数,为18或19的倍数
// windows 始终是整数
zoom = (zoomMode === 'mouse') ? true : (!event.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta))
if (event.shiftKey || event.metaKey || event.ctrlKey) zoom = true
} else {
zoom = !event.shiftKey && (event.metaKey || event.ctrlKey)
}
if (zoom) {
zoomSpeed = within(zoomSpeed, 0, 1)
const min = event.deltaY ? config.delta.y : config.delta.x
scale = within(1 - delta / (min * 4) * zoomSpeed, 0.5, 1.5) // zoomSpeed
}
return scale
}
重点关注 if (zoom) {}
代码块。我们来举个例子,假如我的鼠标deltaY是300,配置项delta.y为100,zoomSpeed 为默认值0.5
鼠标滚动缩小一次:
scale = within(1 - 300/ (100 * 4) * 0.5, 0.5, 1.5) = 0.625
鼠标滚动放大一次:
scale = within(1 + 300/ (100 * 4) * 0.5, 0.5, 1.5) = 1.375
如此一缩一放,画布缩放值=1 * 0.625 * 1.375 = 0.859375,所以看起来元素变小了。
缩放的方案可行性探讨
我们假设画布初始缩放值为s,缩小的时候scale是a,放大的时候scale是b,我们希望sab=s,即a*b=1,这样就能实现一缩一放画布缩放值能回到之前,所以修改 if (zoom) {}
代码块如下:
if (zoom) {
zoomSpeed = within(zoomSpeed, 0, 1)
const min = event.deltaY ? config.delta.y : config.delta.x
const pace = within(1 - Math.abs(delta) / (min * 4) * zoomSpeed, 0.5, 2) // 最大值限制改成了2
scale = delta > 0 ? pace : 1 / pace
}
举个例子测试一下,假如我的鼠标deltaY是300,配置项delta.y为100,zoomSpeed 为默认值0.5
pace = within(1 - 300/ (100 * 4) * 0.5, 0.5, 2) = 0.625
鼠标滚动缩小一次:
scale = 0.625
鼠标滚动放大一次:
scale = 1 / 0.625 = 1.6
如此一缩一放,画布缩放值=1 * 0.625 * 1.6 = 1,画布缩放值回到之前。
不知道这个方案可不可行呢