UNPKG

terriajs

Version:

Geospatial data visualization platform.

127 lines 5.69 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { action } from "mobx"; import { observer } from "mobx-react"; import { useEffect, useRef } from "react"; import styled from "styled-components"; import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3"; import ScreenSpaceEventHandler from "terriajs-cesium/Source/Core/ScreenSpaceEventHandler"; import ScreenSpaceEventType from "terriajs-cesium/Source/Core/ScreenSpaceEventType"; import CommonStrata from "../../../Models/Definition/CommonStrata"; import Text from "../../../Styled/Text"; import LatLonHeightTraits from "../../../Traits/TraitsClasses/LatLonHeightTraits"; const pickScratch = new Cartesian3(); /** * A tool for repositioning the clipping box. * * It moves the clipping box to follow the mouse and places it where the user has clicked. * Action can be cancelled by pressing Escape button. */ const RepositionClippingBox = observer(({ cesium, item }) => { const promptRef = useRef(null); // End repositioning const endRepositioning = action((item) => { item.repositionClippingBoxTrigger = false; // A hacky way to re-compute the boxDrawing so that it gets reset to the // saved trait position. item.clippingBox.setTrait(CommonStrata.user, "showClippingBox", false); window.setTimeout(action(() => item.clippingBox.setTrait(CommonStrata.user, "showClippingBox", true)), 100); }); // Move the clipping box and cursor prompt to follow the mouse const moveItem = (item, canvasCursorPos, cesium) => { const prompt = promptRef.current; if (prompt === null) { return; } const pickPosition = pickGlobePosition(canvasCursorPos, cesium.scene, pickScratch); if (!pickPosition) { return; } const rect = cesium.scene.canvas.getBoundingClientRect(); const offset = 10; // 10px away from the cursor const left = canvasCursorPos.x + rect.left + offset; const top = canvasCursorPos.y + rect.top + offset; if (left <= rect.left) { return; } prompt.style.left = `${left}px`; prompt.style.top = `${top}px`; const boxDrawing = item.clippingBoxDrawing; // A hacky way to set boxDrawing position without setting the traits and // consequently triggering expensive recomputation boxDrawing.setPosition(pickPosition); boxDrawing.onChange?.({ isFinished: false, modelMatrix: boxDrawing.modelMatrix, translationRotationScale: boxDrawing.trs }); }; // Place the clipping box at the screen position const placeItem = (item, screenPosition, cesium) => { const position = pickGlobePosition(screenPosition, cesium.scene, pickScratch); if (!position) { return false; } LatLonHeightTraits.setFromCartesian(item.clippingBox.position, CommonStrata.user, position); return true; }; // Init effect that sets up the event handlers etc. /* eslint-disable-next-line react-hooks/exhaustive-deps */ useEffect(action(function init() { const canvas = cesium.scene.canvas; const boxDrawing = item.clippingBoxDrawing; boxDrawing.stopInteractions(); boxDrawing.enableScaling = false; boxDrawing.enableRotation = false; setCursor(canvas, "crosshair"); cesium.isFeaturePickingPaused = true; if (promptRef.current) setCursor(promptRef.current, "grabbing"); const inputHandler = new ScreenSpaceEventHandler(canvas); inputHandler.setInputAction(({ endPosition }) => { moveItem(item, endPosition, cesium); }, ScreenSpaceEventType.MOUSE_MOVE); inputHandler.setInputAction(({ position }) => placeItem(item, position, cesium) && endRepositioning(item), ScreenSpaceEventType.LEFT_CLICK); const escapeKeyHandler = (ev) => ev.key === "Escape" && endRepositioning(item); document.addEventListener("keydown", escapeKeyHandler); return function destroy() { inputHandler.destroy(); setCursor(canvas, "auto"); if (promptRef.current) setCursor(promptRef.current, "auto"); if (item.clippingBoxDrawing?.dataSource?.show) { item.clippingBoxDrawing.startInteractions(); } document.removeEventListener("keydown", escapeKeyHandler); cesium.isFeaturePickingPaused = false; endRepositioning(item); }; }), [item, cesium]); const initialX = window.innerWidth / 2; const initualY = window.innerHeight / 2; return (_jsxs(CursorPrompt, { ref: promptRef, x: initialX, y: initualY, children: [_jsx(Text, { medium: true, bold: true, style: { marginBottom: "5px" }, children: "Click on map to position clipping box" }), _jsx(Text, { small: true, textAlignCenter: true, children: "Press ESC to cancel" })] })); }); const CursorPrompt = styled.div.attrs(({ x, y }) => ({ style: { left: x + 10, top: y + 10 } })) ` position: absolute; overflow: visible; white-space: nowrap; max-width: 500px; background-color: #2563eb; color: white; padding: 12px; border-radius: 6px; box-shadow: 0px 10px 15px -3px #0000001a; `; function setCursor(el, cursorName) { el.style.cursor = cursorName; } function pickGlobePosition(screenCoords, scene, result) { const pickRay = scene.camera.getPickRay(screenCoords); return pickRay ? scene.globe.pick(pickRay, scene, result) : undefined; } export default RepositionClippingBox; //# sourceMappingURL=RepositionClippingBox.js.map