UNPKG

terriajs

Version:

Geospatial data visualization platform.

107 lines 5.27 kB
import { runInAction } from "mobx"; import { useCallback } from "react"; // Feature detect support for passive: true in event subscriptions. // See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support let passiveSupported = false; try { const options = Object.defineProperty({}, "passive", { get: function () { passiveSupported = true; return true; } }); const callback = () => { return null; }; window.addEventListener("test", callback, options); window.removeEventListener("test", callback, options); } catch (_err) { } const notPassive = passiveSupported ? { passive: false } : false; export const useDragHook = (viewState, padding, thumbSize) => { const drag = useCallback((e) => { let clientX = undefined; let clientY = undefined; if (e instanceof MouseEvent) { clientX = e.clientX; clientY = e.clientY; } else { if (e.targetTouches && e.targetTouches.length > 0) { clientX = e.targetTouches.item(0)?.clientX; clientY = e.targetTouches.item(0)?.clientY; } } if (!clientX || !clientY) return; const viewer = viewState.terria.mainViewer.currentViewer; const container = viewer.getContainer(); const mapRect = container?.getBoundingClientRect(); if (!mapRect) return; let splitFractionX = computeSplitFraction(mapRect.left, mapRect.right, clientX, padding, thumbSize); let splitFractionY = computeSplitFraction(mapRect.top, mapRect.bottom, clientY, padding, thumbSize); // We compute the maximum and minium windows bounds as a percentage so that we can always apply the bounds // restriction as a percentage for consistency (we currently use absolute values for X and percentage values for // Y, but always apply the constraint as a percentage). // We use absolute pixel values for horizontal restriction because of the fixed UI elements which occupy an // absolute amount of screen relestate and 100 px seems like a fine amount for the current UI. // Because the workbench is floating over the map we need to account for it when calculating minX const workbenchVisible = viewState.isMapFullScreen === false && viewState.useSmallScreenInterface === false; const minX = computeSplitFraction(mapRect.left, mapRect.right, mapRect.left + 100 + (workbenchVisible ? 350 : 0), padding, thumbSize); const maxX = computeSplitFraction(mapRect.left, mapRect.right, mapRect.right - 100, padding, thumbSize); // Resctrict to within +/-30% of the center vertically (so we don't run into the top and bottom UI elements). const minY = 0.2; const maxY = 0.8; splitFractionX = Math.min(maxX, Math.max(minX, splitFractionX)); splitFractionY = Math.min(maxY, Math.max(minY, splitFractionY)); runInAction(() => { viewState.terria.splitPosition = splitFractionX; viewState.terria.splitPositionVertical = splitFractionY; }); e.preventDefault(); e.stopPropagation(); }, /* eslint-disable-next-line react-hooks/exhaustive-deps */ [viewState]); const stopDrag = useCallback((e) => { dragUnsubscribe(); const viewer = viewState.terria.currentViewer; // Ensure splitter stays in sync with map viewState.triggerResizeEvent(); viewer.resumeMapInteraction(); e.preventDefault(); e.stopPropagation(); }, /* eslint-disable-next-line react-hooks/exhaustive-deps */ [viewState]); const startDrag = useCallback((e) => { const viewer = viewState.terria.currentViewer; viewer.pauseMapInteraction(); // While dragging is in progress, subscribe to document-level movement and up events. document.addEventListener("mousemove", drag, notPassive); document.addEventListener("touchmove", drag, notPassive); document.addEventListener("mouseup", stopDrag, notPassive); document.addEventListener("touchend", stopDrag, notPassive); e?.preventDefault(); e?.stopPropagation(); }, [drag, stopDrag, viewState]); const dragUnsubscribe = useCallback(() => { document.removeEventListener("mousemove", drag, notPassive); document.removeEventListener("touchmove", drag, notPassive); document.removeEventListener("mouseup", stopDrag, notPassive); document.removeEventListener("touchend", stopDrag, notPassive); }, [drag, stopDrag]); return { startDrag, dragUnsubscribe }; }; function computeSplitFraction(startBound, endBound, position, padding, thumbSize) { const difference = endBound - startBound; const fraction = (position - startBound) / difference; const min = startBound + padding + thumbSize * 0.5; const max = endBound - padding - thumbSize * 0.5; const minFraction = (min - startBound) / difference; const maxFraction = (max - startBound) / difference; return Math.min(maxFraction, Math.max(minFraction, fraction)); } //# sourceMappingURL=dragHook.js.map