以游標為中心縮放的反推公式

滾輪縮放時要讓「游標下方那個世界座標點,縮放後仍對到同一個螢幕位置」,否則畫面會飛走。

做法

const worldBefore = screenToWorld(cursor, viewport)   // 縮放前游標下的世界座標
const nextScale   = viewport.scale * zoomFactor
const offsetX     = cursor.x - worldBefore.x * nextScale
const offsetY     = cursor.y - worldBefore.y * nextScale

原理

想要:worldToScreen(worldBefore, newViewport) === cursor

worldToScreen 公式 screen = world * scale + offset 解出 offset

offset = cursor - worldBefore * nextScale

換句話說:「先用舊 viewport 把游標位置反推成世界座標 → 再用新 scale 算出要把畫布平移多少,才能讓那個世界點仍貼著游標」。

為什麼直覺做法是錯的

如果只改 scale 不調 offset,畫布等於以左上角 (0, 0) 為中心縮放,使用者覺得內容「飛走了」。Figma、Miro、tldraw 全部以游標為中心,這是必備 UX。

相關