kopia lustrzana https://github.com/Tldraw/Tldraw
[improvement] zoom (#577)
* improve zoom events, skip pinch on desktop * Update useZoomEvents.tspull/581/head
rodzic
ee71a37b40
commit
3a08473d85
|
@ -28,23 +28,29 @@ export function useZoomEvents<T extends HTMLElement>(zoom: number, ref: React.Re
|
|||
}, [])
|
||||
|
||||
const handleWheel = React.useCallback<Handler<'wheel', WheelEvent>>(
|
||||
({ delta: wheelDelta, event: e }) => {
|
||||
({ event: e }) => {
|
||||
e.preventDefault()
|
||||
if (inputs.isPinching) return
|
||||
|
||||
const { offset } = normalizeWheel(e)
|
||||
|
||||
// alt+scroll or ctrl+scroll = zoom
|
||||
if ((e.altKey || e.ctrlKey) && e.buttons === 0) {
|
||||
if ((e.altKey || e.ctrlKey || e.metaKey) && e.buttons === 0) {
|
||||
const point = inputs.pointer?.point ?? [bounds.width / 2, bounds.height / 2]
|
||||
const info = inputs.pinch(point, point)
|
||||
const delta = [...point, wheelDelta[1]]
|
||||
const delta = [...point, offset[1]]
|
||||
const info = inputs.pan(delta, e)
|
||||
callbacks.onZoom?.({ ...info, delta }, e)
|
||||
return
|
||||
}
|
||||
// otherwise pan
|
||||
const delta = e.shiftKey
|
||||
? // shift+scroll = pan horizontally
|
||||
[wheelDelta[1], 0]
|
||||
: // scroll = pan vertically (or in any direction on a trackpad)
|
||||
[...wheelDelta]
|
||||
if (inputs.isPinching) return
|
||||
const delta = Vec.mul(
|
||||
e.shiftKey
|
||||
? // shift+scroll = pan horizontally
|
||||
[offset[1], 0]
|
||||
: // scroll = pan vertically (or in any direction on a trackpad)
|
||||
[...offset],
|
||||
0.5
|
||||
)
|
||||
if (Vec.isEqual(delta, [0, 0])) return
|
||||
const info = inputs.pan(delta, e)
|
||||
callbacks.onPan?.(info, e)
|
||||
|
@ -56,6 +62,7 @@ export function useZoomEvents<T extends HTMLElement>(zoom: number, ref: React.Re
|
|||
Handler<'pinch', WheelEvent | PointerEvent | TouchEvent | WebKitGestureEvent>
|
||||
>(
|
||||
({ origin, event }) => {
|
||||
if (event instanceof WheelEvent) return
|
||||
const elm = ref.current
|
||||
if (!elm || !(event.target === elm || elm.contains(event.target as Node))) return
|
||||
const info = inputs.pinch(origin, origin)
|
||||
|
@ -71,7 +78,8 @@ export function useZoomEvents<T extends HTMLElement>(zoom: number, ref: React.Re
|
|||
const handlePinch = React.useCallback<
|
||||
Handler<'pinch', WheelEvent | PointerEvent | TouchEvent | WebKitGestureEvent>
|
||||
>(
|
||||
({ origin, event, offset }) => {
|
||||
({ origin, offset, event }) => {
|
||||
if (event instanceof WheelEvent) return
|
||||
const elm = ref.current
|
||||
if (!(event.target === elm || elm?.contains(event.target as Node))) return
|
||||
if (!rOriginPoint.current) return
|
||||
|
@ -122,3 +130,47 @@ export function useZoomEvents<T extends HTMLElement>(zoom: number, ref: React.Re
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Reasonable defaults
|
||||
const PIXEL_STEP = 10
|
||||
const LINE_HEIGHT = 40
|
||||
const PAGE_HEIGHT = 800
|
||||
|
||||
function normalizeWheel(event: any) {
|
||||
let sX = 0,
|
||||
sY = 0, // spinX, spinY
|
||||
pX = 0,
|
||||
pY = 0 // pixelX, pixelY
|
||||
|
||||
// Legacy
|
||||
if ('detail' in event) sY = event.detail
|
||||
if ('wheelDelta' in event) sY = -event.wheelDelta / 120
|
||||
if ('wheelDeltaY' in event) sY = -event.wheelDeltaY / 120
|
||||
if ('wheelDeltaX' in event) sX = -event.wheelDeltaX / 120
|
||||
|
||||
// side scrolling on FF with DOMMouseScroll
|
||||
if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
|
||||
sX = sY
|
||||
sY = 0
|
||||
}
|
||||
|
||||
pX = 'deltaX' in event ? event.deltaX : sX * PIXEL_STEP
|
||||
pY = 'deltaY' in event ? event.deltaY : sY * PIXEL_STEP
|
||||
|
||||
if ((pX || pY) && event.deltaMode) {
|
||||
if (event.deltaMode == 1) {
|
||||
// delta in LINE units
|
||||
pX *= LINE_HEIGHT
|
||||
pY *= LINE_HEIGHT
|
||||
} else {
|
||||
// delta in PAGE units
|
||||
pX *= PAGE_HEIGHT
|
||||
pY *= PAGE_HEIGHT
|
||||
}
|
||||
}
|
||||
|
||||
// Fall-back if spin cannot be determined
|
||||
if (pX && !sX) sX = pX < 1 ? -1 : 1
|
||||
if (pY && !sY) sY = pY < 1 ? -1 : 1
|
||||
return { spin: [sX, sY], offset: [pX, pY] }
|
||||
}
|
||||
|
|
|
@ -3059,7 +3059,9 @@ export class TldrawApp extends StateManager<TDSnapshot> {
|
|||
return this
|
||||
}
|
||||
|
||||
onPinchStart: TLPinchEventHandler = (info, e) => this.currentTool.onPinchStart?.(info, e)
|
||||
onPinchStart: TLPinchEventHandler = (info, e) => {
|
||||
this.currentTool.onPinchStart?.(info, e)
|
||||
}
|
||||
|
||||
onPinchEnd: TLPinchEventHandler = (info, e) => this.currentTool.onPinchEnd?.(info, e)
|
||||
|
||||
|
@ -3086,12 +3088,12 @@ export class TldrawApp extends StateManager<TDSnapshot> {
|
|||
|
||||
const delta =
|
||||
e.deltaMode === WheelEvent.DOM_DELTA_PIXEL
|
||||
? info.delta[2] / 500
|
||||
? info.delta[2] / 50
|
||||
: e.deltaMode === WheelEvent.DOM_DELTA_LINE
|
||||
? info.delta[2] / 100
|
||||
? info.delta[2] / 50
|
||||
: info.delta[2] / 2
|
||||
|
||||
this.zoomBy(delta, this.centerPoint)
|
||||
this.zoomBy(delta, info.point)
|
||||
this.onPointerMove(info, e as unknown as React.PointerEvent)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
TLKeyboardEventHandler,
|
||||
TLPinchEventHandler,
|
||||
TLPointerEventHandler,
|
||||
TLWheelEventHandler,
|
||||
Utils,
|
||||
} from '@tldraw/core'
|
||||
import type { TldrawApp } from '../internal'
|
||||
|
|
Ładowanie…
Reference in New Issue