From d8236dd8dafbf667b464e3c9465c33fb9fc6e570 Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Thu, 19 Sep 2024 17:26:27 -0400 Subject: [PATCH] Fix zoom callback on camera controls (#3924) --- src/clientSideScene/CameraControls.ts | 42 +++++++++++++++++++++------ src/components/Stream.tsx | 2 +- src/lib/cameraControls.ts | 10 +++---- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/clientSideScene/CameraControls.ts b/src/clientSideScene/CameraControls.ts index 4a1e636335..2cf0394efa 100644 --- a/src/clientSideScene/CameraControls.ts +++ b/src/clientSideScene/CameraControls.ts @@ -444,8 +444,19 @@ export class CameraControls { } onMouseWheel = (event: WheelEvent) => { + const interaction = this.getInteractionType(event) + if (interaction === 'none') return + event.preventDefault() + if (this.syncDirection === 'engineToClient') { - this.zoomDataFromLastFrame = event.deltaY + if (interaction === 'zoom') { + this.zoomDataFromLastFrame = event.deltaY + } else { + // This case will get handled when we add pan and rotate using Apple trackpad. + console.error( + `Unexpected interaction type for engineToClient wheel event: ${interaction}` + ) + } return } @@ -455,8 +466,16 @@ export class CameraControls { // zoom commands to engine. This means dropping some zoom // commands too. // From onMouseMove zoom handling which seems to be really smooth + this.handleStart() - this.pendingZoom = 1 + (event.deltaY / window.devicePixelRatio) * 0.001 + if (interaction === 'zoom') { + this.pendingZoom = 1 + (event.deltaY / window.devicePixelRatio) * 0.001 + } else { + // This case will get handled when we add pan and rotate using Apple trackpad. + console.error( + `Unexpected interaction type for wheel event: ${interaction}` + ) + } this.handleEnd() } @@ -1123,7 +1142,7 @@ export class CameraControls { this.deferReactUpdate(this.reactCameraProperties) Object.values(this._camChangeCallbacks).forEach((cb) => cb()) } - getInteractionType = (event: any) => + getInteractionType = (event: MouseEvent) => _getInteractionType( this.interactionGuards, event, @@ -1231,16 +1250,21 @@ function _lookAt(position: Vector3, target: Vector3, up: Vector3): Quaternion { function _getInteractionType( interactionGuards: MouseGuard, - event: any, + event: MouseEvent | WheelEvent, enablePan: boolean, enableRotate: boolean, enableZoom: boolean ): interactionType | 'none' { - let state: interactionType | 'none' = 'none' - if (enablePan && interactionGuards.pan.callback(event)) return 'pan' - if (enableRotate && interactionGuards.rotate.callback(event)) return 'rotate' - if (enableZoom && interactionGuards.zoom.dragCallback(event)) return 'zoom' - return state + if (event instanceof WheelEvent) { + if (enableZoom && interactionGuards.zoom.scrollCallback(event)) + return 'zoom' + } else { + if (enablePan && interactionGuards.pan.callback(event)) return 'pan' + if (enableRotate && interactionGuards.rotate.callback(event)) + return 'rotate' + if (enableZoom && interactionGuards.zoom.dragCallback(event)) return 'zoom' + } + return 'none' } /** diff --git a/src/components/Stream.tsx b/src/components/Stream.tsx index 3a90f83e58..64a8b5ee40 100644 --- a/src/components/Stream.tsx +++ b/src/components/Stream.tsx @@ -260,7 +260,7 @@ export const Stream = () => { if (state.matches('Sketch')) return if (state.matches({ idle: 'showPlanes' })) return - if (btnName(e).left) { + if (btnName(e.nativeEvent).left) { // eslint-disable-next-line @typescript-eslint/no-floating-promises sendSelectEventToEngine(e, videoRef.current) } diff --git a/src/lib/cameraControls.ts b/src/lib/cameraControls.ts index 48346121fd..8ad6b4930c 100644 --- a/src/lib/cameraControls.ts +++ b/src/lib/cameraControls.ts @@ -6,7 +6,7 @@ const META = PLATFORM === 'macos' ? 'Cmd' : PLATFORM === 'windows' ? 'Win' : 'Super' const ALT = PLATFORM === 'macos' ? 'Option' : 'Alt' -const noModifiersPressed = (e: React.MouseEvent) => +const noModifiersPressed = (e: MouseEvent) => !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey export type CameraSystem = @@ -53,14 +53,14 @@ export function mouseControlsToCameraSystem( interface MouseGuardHandler { description: string - callback: (e: React.MouseEvent) => boolean + callback: (e: MouseEvent) => boolean lenientDragStartButton?: number } interface MouseGuardZoomHandler { description: string - dragCallback: (e: React.MouseEvent) => boolean - scrollCallback: (e: React.MouseEvent) => boolean + dragCallback: (e: MouseEvent) => boolean + scrollCallback: (e: WheelEvent) => boolean lenientDragStartButton?: number } @@ -70,7 +70,7 @@ export interface MouseGuard { rotate: MouseGuardHandler } -export const btnName = (e: React.MouseEvent) => ({ +export const btnName = (e: MouseEvent) => ({ middle: !!(e.buttons & 4) || e.button === 1, right: !!(e.buttons & 2) || e.button === 2, left: !!(e.buttons & 1) || e.button === 0,