From a8fae8d87a29bd44c43bf6480bf6ecf695377237 Mon Sep 17 00:00:00 2001 From: jrmagnus Date: Thu, 10 Sep 2026 23:23:16 -0300 Subject: [PATCH] fix: enable trackpad pinch-to-zoom on the globe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS reports trackpad pinch as wheel events with ctrlKey=true, but Cesium's default zoomEventTypes only binds plain WHEEL (no modifier), so pinch was silently ignored — only two-finger scroll worked. Adds the CTRL-modified WHEEL binding so Cesium recognizes pinch as a zoom gesture, plus a capture-phase relay that amplifies the pinch event's deltaY before Cesium processes it, since macOS reports much smaller deltaY per unit of finger movement for pinch than for scroll (same fixed Cesium formula otherwise made pinch feel unresponsive). --- src/main.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/main.js b/src/main.js index 84fbf12fe..24f8fe0aa 100644 --- a/src/main.js +++ b/src/main.js @@ -125,6 +125,58 @@ async function init() { // 120 Hz hardware; a no-op on 60 Hz displays. (perf item 2) viewer.targetFrameRate = 60; + // macOS trackpad pinch reaches the canvas as a `wheel` event with + // ctrlKey=true (Safari/Chrome both do this so pages can implement their + // own pinch-zoom instead of the OS zooming the whole page). Cesium's + // default zoomEventTypes only binds plain WHEEL (no modifier), so pinch + // events were falling through to no-op — two-finger scroll (plain wheel, + // no ctrlKey) worked, pinch didn't. Add the CTRL-modified WHEEL binding + // so pinch drives zoom the same way scroll does. + viewer.scene.screenSpaceCameraController.zoomEventTypes = [ + Cesium.CameraEventType.RIGHT_DRAG, + Cesium.CameraEventType.WHEEL, + Cesium.CameraEventType.PINCH, + { + eventType: Cesium.CameraEventType.WHEEL, + modifier: Cesium.KeyboardEventModifier.CTRL, + }, + ]; + + // Cesium turns any wheel `delta` into camera movement via the same fixed + // formula regardless of what produced it (arcLength = 7.5deg * delta). + // macOS reports trackpad pinch as wheel+ctrlKey with a much smaller + // deltaY per unit of finger movement than a real two-finger scroll + // produces, so pinch alone reads as "barely moving" even with the + // CTRL-modified zoom binding above. There's no public Cesium knob to + // rescale just the CTRL+WHEEL case, so intercept the raw pinch event + // ahead of Cesium's own listener (capture phase on an ancestor of the + // canvas always runs first) and re-dispatch it with deltaY amplified. + const PINCH_ZOOM_MULTIPLIER = 8; + const PINCH_RELAY_FLAG = '__pinchRelayed'; + viewer.container.addEventListener( + 'wheel', + (event) => { + if (!event.ctrlKey || event[PINCH_RELAY_FLAG]) return; + event.preventDefault(); + event.stopPropagation(); + const relayed = new WheelEvent('wheel', { + deltaX: event.deltaX, + deltaY: event.deltaY * PINCH_ZOOM_MULTIPLIER, + deltaZ: event.deltaZ, + deltaMode: event.deltaMode, + clientX: event.clientX, + clientY: event.clientY, + ctrlKey: true, + bubbles: true, + cancelable: true, + view: window, + }); + relayed[PINCH_RELAY_FLAG] = true; + viewer.canvas.dispatchEvent(relayed); + }, + { capture: true, passive: false }, + ); + // Register per-layer data attribution into the "Data attribution" popover. // Required by each source's license (ODbL, CC BY-NC-SA, NASA FIRMS, etc.); // strings are verbatim from DATA_SOURCES.md. Static + always-present in the