UNPKG

terriajs

Version:

Geospatial data visualization platform.

141 lines 6.36 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import L from "leaflet"; import { runInAction } from "mobx"; import { observer } from "mobx-react"; import { useEffect, useState } from "react"; import { useTheme } from "styled-components"; import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic"; import isDefined from "../../../Core/isDefined"; import Box from "../../../Styled/Box"; import Text from "../../../Styled/Text"; import { useViewState } from "../../Context"; const geodesic = new EllipsoidGeodesic(); const distances = [ 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1000, 2000, 3000, 5000, 10000, 20000, 30000, 50000, 100000, 200000, 300000, 500000, 1000000, 2000000, 3000000, 5000000, 10000000, 20000000, 30000000, 50000000 ]; export const DistanceLegend = observer(({ scale = 1, isPrintMode = false }) => { const [distanceLabel, setDistanceLabel] = useState(); const [barWidth, setBarWidth] = useState(0); const { terria } = useViewState(); const theme = useTheme(); let removeUpdateSubscription; useEffect(() => { const viewerSubscriptions = []; /* eslint-disable-next-line react-hooks/exhaustive-deps */ removeUpdateSubscription = addUpdateSubscription(); return () => { if (removeUpdateSubscription) { removeUpdateSubscription(); } viewerSubscriptions.forEach((clear) => clear()); }; }, [terria.cesium, terria.leaflet]); const addUpdateSubscription = () => { if (isDefined(terria.cesium)) { const scene = terria.cesium.scene; let removeUpdateSubscription = scene.postRender.addEventListener(() => { updateDistanceLegendCesium(scene); if (isPrintMode) { removeUpdateSubscription?.(); removeUpdateSubscription = undefined; } }); return removeUpdateSubscription; } else if (isDefined(terria.leaflet)) { const map = terria.leaflet.map; let removeUpdateSubscription = undefined; if (!isPrintMode) { const potentialChangeCallback = function potentialChangeCallback() { updateDistanceLegendLeaflet(map); }; removeUpdateSubscription = function () { map.off("zoomend", potentialChangeCallback); map.off("moveend", potentialChangeCallback); }; map.on("zoomend", potentialChangeCallback); map.on("moveend", potentialChangeCallback); } updateDistanceLegendLeaflet(map); return removeUpdateSubscription; } }; const updateDistanceLegendCesium = (scene) => { // Find the distance between two pixels at the bottom center of the screen. const width = scene.canvas.clientWidth; const height = scene.canvas.clientHeight; const left = scene.camera.getPickRay(new Cartesian2((width / 2) | 0, height - 1)); const right = scene.camera.getPickRay(new Cartesian2((1 + width / 2) | 0, height - 1)); const globe = scene.globe; if (!isDefined(left) || !isDefined(right)) { return; } const leftPosition = globe.pick(left, scene); const rightPosition = globe.pick(right, scene); if (!isDefined(leftPosition) || !isDefined(rightPosition)) { setBarWidth(0); setDistanceLabel(undefined); return; } const leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition); const rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition); geodesic.setEndPoints(leftCartographic, rightCartographic); const pixelDistance = geodesic.surfaceDistance; runInAction(() => (terria.mainViewer.scale = pixelDistance)); // Find the first distance that makes the scale bar less than 100 pixels. const maxBarWidth = 100; let distance; for (let i = distances.length - 1; !isDefined(distance) && i >= 0; --i) { if (distances[i] / pixelDistance < maxBarWidth) { distance = distances[i]; } } if (isDefined(distance)) { let label; if (distance >= 1000) { label = (distance / 1000).toString() + " km"; } else { label = distance.toString() + " m"; } setBarWidth(((distance / pixelDistance) * scale) | 0); setDistanceLabel(label); } else { setBarWidth(0); setDistanceLabel(undefined); } }; const updateDistanceLegendLeaflet = (map) => { const halfHeight = map.getSize().y / 2; const maxPixelWidth = 100; const maxMeters = map .containerPointToLatLng([0, halfHeight]) .distanceTo(map.containerPointToLatLng([maxPixelWidth, halfHeight])); runInAction(() => (terria.mainViewer.scale = maxMeters / 100)); // @ts-expect-error Accessing private method const meters = L.control.scale()._getRoundNum(maxMeters); const label = meters < 1000 ? meters + " m" : meters / 1000 + " km"; setBarWidth((meters / maxMeters) * maxPixelWidth * scale); setDistanceLabel(label); }; const barStyle = { width: barWidth + "px", left: 5 + (125 - barWidth) / 2 + "px", height: "2px" }; return distanceLabel ? (_jsxs(Box, { column: true, centered: true, css: ` margin-top: 3px; margin-bottom: 3px; &:hover { background-color: ${theme.charcoalGrey}; } `, paddedHorizontally: 2, className: "tjs-legend__distanceLegend", children: [_jsx(Text, { as: "label", mono: true, styledLineHeight: "1", textLight: true, styledFontSize: "inherit", children: distanceLabel }), _jsx("div", { style: barStyle, className: "tjs-legend__bar", css: { backgroundColor: theme.textLight, transition: "all 0.5s ease-in-out 0s" } })] })) : null; }); //# sourceMappingURL=DistanceLegend.js.map