UNPKG

terriajs

Version:

Geospatial data visualization platform.

278 lines 16.1 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { action } from "mobx"; import { observer } from "mobx-react"; import Slider from "rc-slider"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; import SplitDirection from "terriajs-cesium/Source/Scene/SplitDirection"; import CatalogMemberMixin from "../../../ModelMixins/CatalogMemberMixin"; import MappableMixin from "../../../ModelMixins/MappableMixin"; import Cesium from "../../../Models/Cesium"; import ViewerMode, { MapViewers, getViewerType, isViewerMode, setViewerMode } from "../../../Models/ViewerMode"; import Box from "../../../Styled/Box"; import Button, { RawButton } from "../../../Styled/Button"; import Checkbox from "../../../Styled/Checkbox"; import { GLYPHS, StyledIcon } from "../../../Styled/Icon"; import Spacing from "../../../Styled/Spacing"; import Text, { TextSpan } from "../../../Styled/Text"; import { useViewState } from "../../Context"; import { useRefForTerria } from "../../Hooks/useRefForTerria"; import MenuPanel from "../../StandardUserInterface/customizable/MenuPanel"; import Styles from "./setting-panel.scss"; const sides = { left: "settingPanel.terrain.left", both: "settingPanel.terrain.both", right: "settingPanel.terrain.right" }; const SettingPanel = observer(() => { const { t } = useTranslation(); const viewState = useViewState(); const { terria } = viewState; const settingButtonRef = useRefForTerria(SETTING_PANEL_NAME, viewState); const [hoverBaseMap, setHoverBaseMap] = useState(); const activeMap = hoverBaseMap ?? terria.mainViewer.baseMap; const activeMapName = activeMap ? mapDisplayName(activeMap) : "(None)"; const selectBaseMap = (baseMap, event) => { event.stopPropagation(); if (!MappableMixin.isMixedInto(baseMap)) return; const currentViewerMode = terria.mainViewer.viewerMode; const newViewerMode = baseMap.preferredViewerMode ? getViewerType(baseMap.preferredViewerMode) : undefined; terria.mainViewer.setBaseMap(baseMap).then(() => { const switchedViewerMode = newViewerMode && currentViewerMode && newViewerMode !== currentViewerMode && terria.mainViewer.viewerMode === newViewerMode; if (switchedViewerMode) { notifyViewerModeSwitch(baseMap, currentViewerMode, newViewerMode, terria, t); } }); // We store the user's chosen basemap for future use, but it's up to the instance to decide // whether to use that at start up. if (baseMap) { saveBaseMapPreference(terria, baseMap); } }; const mouseEnterBaseMap = (baseMap) => { setHoverBaseMap(baseMap.item); }; const mouseLeaveBaseMap = () => { setHoverBaseMap(undefined); }; const selectViewer = action((viewer, event) => { const mainViewer = terria.mainViewer; event.stopPropagation(); showTerrainOnSide(sides.both, undefined); setViewerMode(viewer, mainViewer); // Ensure a base map that is compatible with the new viewer mode const prevBaseMap = mainViewer.baseMap; mainViewer.useViewerCompatibleBaseMap().then((baseMapChanged) => { if (baseMapChanged && mainViewer.baseMap) { saveBaseMapPreference(terria, mainViewer.baseMap); if (prevBaseMap) { notifyBaseMapSwitch(terria, mainViewer, prevBaseMap, mainViewer.baseMap, t); } } }); // We store the user's chosen viewer mode for future use. terria.setLocalProperty("viewermode", viewer); terria.currentViewer.notifyRepaintRequired(); }); const showTerrainOnSide = action((side, event) => { event?.stopPropagation(); switch (side) { case sides.left: terria.terrainSplitDirection = SplitDirection.LEFT; terria.showSplitter = true; break; case sides.right: terria.terrainSplitDirection = SplitDirection.RIGHT; terria.showSplitter = true; break; case sides.both: terria.terrainSplitDirection = SplitDirection.NONE; break; } terria.currentViewer.notifyRepaintRequired(); }); const toggleDepthTestAgainstTerrainEnabled = action((event) => { event.stopPropagation(); terria.depthTestAgainstTerrainEnabled = !terria.depthTestAgainstTerrainEnabled; terria.currentViewer.notifyRepaintRequired(); }); const onBaseMaximumScreenSpaceErrorChange = (bmsse) => { terria.setBaseMaximumScreenSpaceError(bmsse); terria.setLocalProperty("baseMaximumScreenSpaceError", bmsse.toString()); }; const toggleUseNativeResolution = () => { terria.setUseNativeResolution(!terria.useNativeResolution); terria.setLocalProperty("useNativeResolution", terria.useNativeResolution); }; const qualityLabels = { 0: t("settingPanel.qualityLabels.maximumPerformance"), 1: t("settingPanel.qualityLabels.balancedPerformance"), 2: t("settingPanel.qualityLabels.lowerPerformance") }; const currentViewer = terria.mainViewer.viewerMode === ViewerMode.Cesium ? terria.mainViewer.viewerOptions.useTerrain ? "3d" : "3dsmooth" : "2d"; const useNativeResolution = terria.useNativeResolution; const nativeResolutionLabel = t("settingPanel.nativeResolutionLabel", { resolution1: useNativeResolution ? t("settingPanel.native") : t("settingPanel.screen"), resolution2: useNativeResolution ? t("settingPanel.screen") : t("settingPanel.native") }); const dropdownTheme = { inner: Styles.dropdownInner, icon: "map" }; const isCesiumWithTerrain = terria.mainViewer.viewerMode === ViewerMode.Cesium && terria.mainViewer.viewerOptions.useTerrain && terria.currentViewer && terria.currentViewer instanceof Cesium && terria.currentViewer.scene && terria.currentViewer.scene.globe; const supportsDepthTestAgainstTerrain = isCesiumWithTerrain; const depthTestAgainstTerrainEnabled = supportsDepthTestAgainstTerrain && terria.depthTestAgainstTerrainEnabled; const depthTestAgainstTerrainLabel = depthTestAgainstTerrainEnabled ? t("settingPanel.terrain.showUndergroundFeatures") : t("settingPanel.terrain.hideUndergroundFeatures"); if (terria.configParameters.useCesiumIonTerrain || terria.configParameters.cesiumTerrainUrl) { MapViewers["3d"].available = true; } const supportsSide = isCesiumWithTerrain; let currentSide = sides.both; if (supportsSide) { switch (terria.terrainSplitDirection) { case SplitDirection.LEFT: currentSide = sides.left; break; case SplitDirection.RIGHT: currentSide = sides.right; break; } } const timelineStack = terria.timelineStack; const alwaysShowTimelineLabel = timelineStack.alwaysShowingTimeline ? t("settingPanel.timeline.alwaysShowLabel") : t("settingPanel.timeline.hideLabel"); const baseMapStatusMessage = terria.mainViewer.baseMap && getBaseMapStatusMessage(terria.mainViewer.baseMap, t); return ( //@ts-expect-error - not yet ready to tackle tsfying MenuPanel _jsx(MenuPanel, { theme: dropdownTheme, btnRef: settingButtonRef, btnTitle: t("settingPanel.btnTitle"), btnText: t("settingPanel.btnText"), viewState: viewState, smallScreen: viewState.useSmallScreenInterface, isOpen: viewState.settingsPanelIsVisible, onOpenChanged: action((isOpen) => { viewState.settingsPanelIsVisible = isOpen; }), children: _jsxs(Box, { paddedRatio: 3, column: true, children: [_jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.mapView") }) }), _jsx(FlexGrid, { gap: 1, elementsNo: 3, children: Object.entries(MapViewers).map(([key, viewerMode]) => (_jsx(SettingsButton, { isActive: key === currentViewer, onClick: (event) => selectViewer(key, event), children: _jsx(Text, { mini: true, children: t(viewerMode.label) }) }, key))) }), !!supportsSide && (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 2 }), _jsxs(Box, { column: true, children: [_jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.terrain.sideLabel") }) }), _jsx(FlexGrid, { gap: 1, elementsNo: 3, children: Object.values(sides).map((side) => (_jsx(SettingsButton, { isActive: side === currentSide, onClick: (event) => showTerrainOnSide(side, event), children: _jsx(Text, { mini: true, children: t(side) }) }, side))) })] }), !!supportsDepthTestAgainstTerrain && (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 2 }), _jsx(Checkbox, { textProps: { small: true }, id: "depthTestAgainstTerrain", title: depthTestAgainstTerrainLabel, isChecked: depthTestAgainstTerrainEnabled, onChange: toggleDepthTestAgainstTerrainEnabled, children: _jsx(TextSpan, { children: t("settingPanel.terrain.hideUnderground") }) })] }))] })), _jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 2 }), _jsxs(Box, { column: true, children: [_jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.baseMap") }) }), _jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", mini: true, children: activeMapName }) }), _jsx(FlexGrid, { gap: 1, elementsNo: 4, children: terria.baseMapsModel.baseMapItems.map((baseMap, i) => (_jsxs(StyledBasemapButton, { isActive: baseMap.item === terria.mainViewer.baseMap, onClick: (event) => selectBaseMap(baseMap.item, event), onMouseEnter: () => mouseEnterBaseMap(baseMap), onMouseLeave: mouseLeaveBaseMap, onFocus: () => mouseEnterBaseMap(baseMap), "data-test-id": `baseMap-${i}`, "data-current-basemap": baseMap.item === terria.mainViewer.baseMap ? true : undefined, children: [baseMap.item === terria.mainViewer.baseMap ? (_jsx(Box, { position: "absolute", topRight: true, children: _jsx(StyledIcon, { light: true, glyph: GLYPHS.selected, styledWidth: "22px" }) })) : null, _jsx(StyledImage, { fullWidth: true, alt: baseMap.item ? baseMap.item.name : "", src: baseMap.image })] }, baseMap.item?.uniqueId))) }), baseMapStatusMessage && (_jsx(BaseMapStatus, { children: baseMapStatusMessage }))] })] }), _jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 2 }), _jsxs(Box, { column: true, children: [_jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.timeline.title") }) }), _jsx(Checkbox, { textProps: { small: true }, id: "alwaysShowTimeline", isChecked: timelineStack.alwaysShowingTimeline, title: alwaysShowTimelineLabel, onChange: () => { timelineStack.setAlwaysShowTimeline(!timelineStack.alwaysShowingTimeline); }, children: _jsx(TextSpan, { children: t("settingPanel.timeline.alwaysShow") }) })] })] }), terria.mainViewer.viewerMode !== ViewerMode.Leaflet && (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 2 }), _jsxs(Box, { column: true, children: [_jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.imageOptimisation") }) }), _jsx(Checkbox, { textProps: { small: true }, id: "mapUseNativeResolution", isChecked: useNativeResolution, title: nativeResolutionLabel, onChange: () => toggleUseNativeResolution(), children: _jsx(TextSpan, { children: t("settingPanel.nativeResolutionHeader") }) }), _jsx(Spacing, { bottom: 2 }), _jsx(Box, { paddedVertically: 1, children: _jsx(Text, { as: "label", children: t("settingPanel.mapQuality") }) }), _jsxs(Box, { verticalCenter: true, children: [_jsx(Text, { mini: true, children: t("settingPanel.qualityLabel") }), _jsx(Slider, { min: 1, max: 3, step: 0.1, value: terria.baseMaximumScreenSpaceError, onChange: (val) => onBaseMaximumScreenSpaceErrorChange(val), marks: { 2: "" }, "aria-valuetext": qualityLabels, css: ` margin: 0 10px; margin-top: 5px; ` }), _jsx(Text, { mini: true, children: t("settingPanel.performanceLabel") })] })] })] }))] }) })); }); /** * Return name + CRS if the base map specifies one */ function mapDisplayName(baseMap) { const name = (CatalogMemberMixin.isMixedInto(baseMap) ? baseMap.name : undefined) ?? ""; return name; } /** * Save user's base map preference */ function saveBaseMapPreference(terria, baseMap) { if (baseMap.uniqueId) { terria.setLocalProperty("basemap", baseMap.uniqueId); } } /** * Notify user about switching base map to a viewer compatible base map */ function notifyBaseMapSwitch(terria, viewer, currentBaseMap, newBaseMap, t) { const viewerMode = viewer.viewerMode; terria.notificationState.addNotificationToQueue({ title: t("settingPanel.baseMapSwitched.title"), message: t("settingPanel.baseMapSwitched.message", { currentBaseMap: mapDisplayName(currentBaseMap), newBaseMap: mapDisplayName(newBaseMap), mapMode: viewer.viewerMode === ViewerMode.Cesium ? "3D" : "2D" }), ignore: () => // auto-dismiss notification if state changes viewer.baseMap !== newBaseMap || viewer.viewerMode !== viewerMode, showAsToast: true, toastVisibleDuration: 10 }); } function notifyViewerModeSwitch(newBaseMap, currentViewerMode, newViewerMode, terria, t) { const viewer = terria.mainViewer; terria.notificationState.addNotificationToQueue({ title: t("settingPanel.viewerModeSwitched.title"), message: t("settingPanel.viewerModeSwitched.message", { newBaseMap: mapDisplayName(newBaseMap), currentMode: currentViewerMode === ViewerMode.Cesium ? "3D" : "2D", newMode: newViewerMode === ViewerMode.Cesium ? "3D" : "2D" }), ignore: () => // auto-dismiss notification if state changes viewer.viewerMode !== newViewerMode || viewer.baseMap !== newBaseMap, showAsToast: true, toastVisibleDuration: 15 }); } /** * Returns a status message to show when the given base map is selected. * * Currently this returns a message if the base map requires a specific viewer * mode. */ function getBaseMapStatusMessage(baseMap, t) { const viewerMode = baseMap.preferredViewerMode && isViewerMode(baseMap.preferredViewerMode) ? baseMap.preferredViewerMode.slice(0, 2).toLocaleUpperCase() : undefined; if (viewerMode) { return t("settingPanel.baseMapStatus.requiresViewerMode", { viewerMode }); } } export const SETTING_PANEL_NAME = "MenuBarMapSettingsButton"; export default SettingPanel; const FlexGrid = styled(Box).attrs({ flexWrap: true }) ` gap: ${(props) => props.gap * 5}px; > * { flex: ${(props) => `1 0 ${getCalcWidth(props.elementsNo, props.gap)}`}; max-width: ${(props) => getCalcWidth(props.elementsNo, props.gap)}; } `; const getCalcWidth = (elementsNo, gap) => `calc(${100 / elementsNo}% - ${gap * 5}px)`; const SettingsButton = styled(Button) ` background-color: ${(props) => props.theme.overlay}; border: 1px solid ${(props) => (props.isActive ? "rgba(255, 255, 255, 0.5)" : "transparent")}; `; const StyledBasemapButton = styled(RawButton) ` border-radius: 4px; position: relative; border: 2px solid ${(props) => props.isActive ? props.theme.turquoiseBlue : "rgba(255, 255, 255, 0.5)"}; `; const StyledImage = styled(Box).attrs({ as: "img" }) ` border-radius: inherit; `; const BaseMapStatus = styled(Text) ` font-size: 11px; padding: ${(p) => p.theme.padding} 0; `; //# sourceMappingURL=SettingPanel.js.map