diff --git a/CHANGES.md b/CHANGES.md index 7c0439144b9..708326ac916 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ #### next release (8.3.4) +- Move map credits to map column so it don't get hidden by chart panel +- TSify `MapColumn` module and reorganize components directory structure. +- Add null check to `WebMapServiceCatalogItem` `rectangle` calculation - and now we ascend tree of WMS `Layers` until we find a rectangle. - Add `timeWindowDuration`, `timeWindowUnit` and `isForwardTimeWindow` traits to esri-mapServer type to support time window query. - [The next improvement] diff --git a/lib/Models/Catalog/Ows/WebMapServiceCapabilities.ts b/lib/Models/Catalog/Ows/WebMapServiceCapabilities.ts index 411c1074c62..bffbafb677a 100644 --- a/lib/Models/Catalog/Ows/WebMapServiceCapabilities.ts +++ b/lib/Models/Catalog/Ows/WebMapServiceCapabilities.ts @@ -151,6 +151,10 @@ export function getRectangleFromLayer( }; } } + + // Work way through ancestors until we get a rectangle. + if (layer._parent) return getRectangleFromLayer(layer._parent); + return undefined; } diff --git a/lib/Models/Catalog/Ows/WebMapServiceCapabilitiesStratum.ts b/lib/Models/Catalog/Ows/WebMapServiceCapabilitiesStratum.ts index 2460647f578..8cb7bff5b01 100644 --- a/lib/Models/Catalog/Ows/WebMapServiceCapabilitiesStratum.ts +++ b/lib/Models/Catalog/Ows/WebMapServiceCapabilitiesStratum.ts @@ -638,17 +638,27 @@ export default class WebMapServiceCapabilitiesStratum extends LoadableStratum( (unionRectangle, layer) => { // Convert to cesium Rectangle (so we can use Rectangle.union) const latLonRect = getRectangleFromLayer(layer); - const ceisumRect = Rectangle.fromDegrees( + + if ( + !isDefined(latLonRect?.west) || + !isDefined(latLonRect?.south) || + !isDefined(latLonRect?.east) || + !isDefined(latLonRect?.north) + ) + return; + + const cesiumRectangle = Rectangle.fromDegrees( latLonRect?.west, latLonRect?.south, latLonRect?.east, latLonRect?.north ); + if (!unionRectangle) { - return ceisumRect; + return cesiumRectangle; } - return Rectangle.union(unionRectangle, ceisumRect); + return Rectangle.union(unionRectangle, cesiumRectangle); }, undefined ); diff --git a/lib/Models/Terria.ts b/lib/Models/Terria.ts index 81f8cc049aa..38a7eed4086 100644 --- a/lib/Models/Terria.ts +++ b/lib/Models/Terria.ts @@ -70,7 +70,7 @@ import TimeVarying from "../ModelMixins/TimeVarying"; import { HelpContentItem } from "../ReactViewModels/defaultHelpContent"; import { defaultTerms, Term } from "../ReactViewModels/defaultTerms"; import NotificationState from "../ReactViewModels/NotificationState"; -import { ICredit } from "../ReactViews/Credits"; +import { ICredit } from "../ReactViews/Map/BottomBar/Credits"; import { SHARE_VERSION } from "../ReactViews/Map/Panels/SharePanel/BuildShareLink"; import { shareConvertNotification } from "../ReactViews/Notification/shareConvertNotification"; import MappableTraits from "../Traits/TraitsClasses/MappableTraits"; diff --git a/lib/ReactViewModels/MouseCoords.ts b/lib/ReactViewModels/MouseCoords.ts index 409e4e56346..f68381192b2 100644 --- a/lib/ReactViewModels/MouseCoords.ts +++ b/lib/ReactViewModels/MouseCoords.ts @@ -79,12 +79,13 @@ export default class MouseCoords { ); } - @action + @action.bound toggleUseProjection() { this.useProjection = !this.useProjection; this.updateEvent.raiseEvent(); } + @action updateCoordinatesFromCesium(terria: Terria, position: Cartesian2) { if (!terria.cesium) { return; @@ -187,6 +188,7 @@ export default class MouseCoords { } } + @action updateCoordinatesFromLeaflet(terria: Terria, mouseMoveEvent: MouseEvent) { if (!terria.leaflet) { return; diff --git a/lib/ReactViews/ActionBar/ActionBar.tsx b/lib/ReactViews/ActionBar/ActionBar.tsx index 937d2127b2c..5ddefabe205 100644 --- a/lib/ReactViews/ActionBar/ActionBar.tsx +++ b/lib/ReactViews/ActionBar/ActionBar.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import styled from "styled-components"; import Box from "../../Styled/Box"; import { PortalChild } from "../StandardUserInterface/Portal"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { ActionBarPortalId } from "./ActionBarPortal"; /** diff --git a/lib/ReactViews/BottomDock/BottomDock.tsx b/lib/ReactViews/BottomDock/BottomDock.tsx index 900ccd370d3..d5bd89c0992 100644 --- a/lib/ReactViews/BottomDock/BottomDock.tsx +++ b/lib/ReactViews/BottomDock/BottomDock.tsx @@ -10,13 +10,13 @@ import Styles from "./bottom-dock.scss"; import ChartDisclaimer from "./ChartDisclaimer"; import Timeline from "./Timeline/Timeline"; -interface PropsType extends MeasureElementProps { +interface PropsType { terria: Terria; viewState: ViewState; } @observer -class BottomDock extends React.Component { +class BottomDock extends React.Component { refToMeasure: HTMLDivElement | null = null; handleClick() { @@ -25,7 +25,7 @@ class BottomDock extends React.Component { }); } - componentDidUpdate(prevProps: PropsType) { + componentDidUpdate(prevProps: PropsType & MeasureElementProps) { if ( prevProps.heightFromMeasureElementHOC !== this.props.heightFromMeasureElementHOC diff --git a/lib/ReactViews/StandardUserInterface/ContextProviders.tsx b/lib/ReactViews/Context/ContextProviders.tsx similarity index 91% rename from lib/ReactViews/StandardUserInterface/ContextProviders.tsx rename to lib/ReactViews/Context/ContextProviders.tsx index 44bc042c5e6..06854c0c0de 100644 --- a/lib/ReactViews/StandardUserInterface/ContextProviders.tsx +++ b/lib/ReactViews/Context/ContextProviders.tsx @@ -3,7 +3,7 @@ import { DefaultTheme, ThemeProvider } from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; import { ViewStateProvider } from "./ViewStateContext"; -export default (props: { +export const ContextProviders = (props: { viewState: ViewState; theme: DefaultTheme | ((theme: DefaultTheme) => DefaultTheme); children: React.ReactNode[]; diff --git a/lib/ReactViews/StandardUserInterface/ViewStateContext.tsx b/lib/ReactViews/Context/ViewStateContext.tsx similarity index 100% rename from lib/ReactViews/StandardUserInterface/ViewStateContext.tsx rename to lib/ReactViews/Context/ViewStateContext.tsx diff --git a/lib/ReactViews/Context/index.ts b/lib/ReactViews/Context/index.ts new file mode 100644 index 00000000000..fba95c1445c --- /dev/null +++ b/lib/ReactViews/Context/index.ts @@ -0,0 +1,2 @@ +export * from "./ViewStateContext"; +export * from "./ContextProviders"; diff --git a/lib/ReactViews/Credits/index.ts b/lib/ReactViews/Credits/index.ts deleted file mode 100644 index c64853d9cd8..00000000000 --- a/lib/ReactViews/Credits/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ICredit } from "./Credit.type"; -export { MapCredits } from "./MapCredits/MapCredits"; diff --git a/lib/ReactViews/Custom/ExternalLink.tsx b/lib/ReactViews/Custom/ExternalLink.tsx index a82e7964c3e..5d6669b974e 100644 --- a/lib/ReactViews/Custom/ExternalLink.tsx +++ b/lib/ReactViews/Custom/ExternalLink.tsx @@ -1,7 +1,7 @@ import { AnchorHTMLAttributes, default as React } from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; const Icon = require("../../Styled/Icon").default; const { StyledIcon } = require("../../Styled/Icon"); diff --git a/lib/ReactViews/Disclaimer.jsx b/lib/ReactViews/Disclaimer.jsx index d5660523e83..656ec1ef8f7 100644 --- a/lib/ReactViews/Disclaimer.jsx +++ b/lib/ReactViews/Disclaimer.jsx @@ -12,7 +12,7 @@ import Button from "../Styled/Button"; import Spacing from "../Styled/Spacing"; import Text from "../Styled/Text"; import parseCustomMarkdownToReact from "./Custom/parseCustomMarkdownToReact"; -import { withViewState } from "./StandardUserInterface/ViewStateContext"; +import { withViewState } from "./Context"; import FadeIn from "./Transitions/FadeIn/FadeIn"; const TopElementBox = styled(Box)` diff --git a/lib/ReactViews/DragDropFile.tsx b/lib/ReactViews/DragDropFile.tsx index 3016c81ec5f..2dec3623ea3 100644 --- a/lib/ReactViews/DragDropFile.tsx +++ b/lib/ReactViews/DragDropFile.tsx @@ -14,10 +14,7 @@ import MappableMixin from "../ModelMixins/MappableMixin"; import addUserFiles from "../Models/Catalog/addUserFiles"; import { BaseModel } from "../Models/Definition/Model"; import Styles from "./drag-drop-file.scss"; -import { - WithViewState, - withViewState -} from "./StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "./Context"; import { raiseFileDragDropEvent } from "../ViewModels/FileDragDropListener"; interface PropsType extends WithTranslation, WithViewState {} diff --git a/lib/ReactViews/DragDropNotification.jsx b/lib/ReactViews/DragDropNotification.jsx index fec17f6ab94..63bf30c8c7d 100644 --- a/lib/ReactViews/DragDropNotification.jsx +++ b/lib/ReactViews/DragDropNotification.jsx @@ -6,7 +6,7 @@ import PropTypes from "prop-types"; import React from "react"; import Icon from "../Styled/Icon"; import Styles from "./drag-drop-notification.scss"; -import { withViewState } from "./StandardUserInterface/ViewStateContext"; +import { withViewState } from "./Context"; @observer class DragDropNotification extends React.Component { diff --git a/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx b/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx index 91dac320a8b..5ed52578fe7 100644 --- a/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx +++ b/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx @@ -2,7 +2,7 @@ import { action } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import ViewState from "../../ReactViewModels/ViewState"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import ModalPopup from "./ModalPopup"; import Tabs from "./Tabs"; diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx index d68d0433d9b..437ed11cab6 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx @@ -6,7 +6,7 @@ import filterOutUndefined from "../../Core/filterOutUndefined"; import JsonValue, { JsonObject } from "../../Core/Json"; import ViewState from "../../ReactViewModels/ViewState"; import Icon from "../../Styled/Icon"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./feature-info-download.scss"; const Dropdown = require("../Generic/Dropdown"); diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx index 656ead4cf06..5d45367fb28 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx @@ -29,7 +29,7 @@ import Workbench from "../../Models/Workbench"; import ViewState from "../../ReactViewModels/ViewState"; import Icon from "../../Styled/Icon"; import Loader from "../Loader"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./feature-info-panel.scss"; import FeatureInfoCatalogItem from "./FeatureInfoCatalogItem"; diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx index ea9ad19bc4f..58ea83eab25 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx @@ -31,10 +31,7 @@ import FeatureInfoContext from "../../Models/Feature/FeatureInfoContext"; import Icon from "../../Styled/Icon"; import { FeatureInfoPanelButton as FeatureInfoPanelButtonModel } from "../../ViewModels/FeatureInfoPanel"; import parseCustomMarkdownToReact from "../Custom/parseCustomMarkdownToReact"; -import { - withViewState, - WithViewState -} from "../StandardUserInterface/ViewStateContext"; +import { withViewState, WithViewState } from "../Context"; import Styles from "./feature-info-section.scss"; import FeatureInfoDownload from "./FeatureInfoDownload"; import FeatureInfoPanelButton from "./FeatureInfoPanelButton"; diff --git a/lib/ReactViews/Feedback/FeedbackForm.tsx b/lib/ReactViews/Feedback/FeedbackForm.tsx index 54a68d88045..675f47de837 100644 --- a/lib/ReactViews/Feedback/FeedbackForm.tsx +++ b/lib/ReactViews/Feedback/FeedbackForm.tsx @@ -16,10 +16,7 @@ import Text from "../../Styled/Text"; import parseCustomMarkdownToReact, { parseCustomMarkdownToReactWithOptions } from "../Custom/parseCustomMarkdownToReact"; -import { - WithViewState, - withViewState -} from "../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../Context"; import { applyTranslationIfExists } from "./../../Language/languageHelpers"; interface IProps extends WithTranslation, WithViewState { diff --git a/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx b/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx index 57aa0fbfcd2..5bf038c3956 100644 --- a/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx +++ b/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; import React from "react"; import { useTranslation } from "react-i18next"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import HelpPrompt from "./HelpPrompt"; export const SATELLITE_HELP_PROMPT_KEY = "satelliteGuidance"; diff --git a/lib/ReactViews/Map/BottomBar/BottomBar.tsx b/lib/ReactViews/Map/BottomBar/BottomBar.tsx new file mode 100644 index 00000000000..cd903ba6e3c --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/BottomBar.tsx @@ -0,0 +1,32 @@ +import { VFC } from "react"; +import Box from "../../../Styled/Box"; +import { useViewState } from "../../Context"; +import { MapCredits } from "./Credits"; +import { DistanceLegend } from "./DistanceLegend"; +import { LocationBar } from "./LocationBar"; +import React from "react"; + +export const BottomBar: VFC = () => { + const viewState = useViewState(); + return ( + + + + + + + + ); +}; diff --git a/lib/ReactViews/Credits/Credit.tsx b/lib/ReactViews/Map/BottomBar/Credits/Credit.tsx similarity index 89% rename from lib/ReactViews/Credits/Credit.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Credit.tsx index 5901407ea9c..751297ff0f7 100644 --- a/lib/ReactViews/Credits/Credit.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/Credit.tsx @@ -1,6 +1,6 @@ import React, { FC } from "react"; import { useTranslation } from "react-i18next"; -import { ExternalLinkIcon } from "../Custom/ExternalLink"; +import { ExternalLinkIcon } from "../../../Custom/ExternalLink"; import { ICredit } from "./Credit.type"; import { Spacer } from "./Spacer"; diff --git a/lib/ReactViews/Credits/Credit.type.ts b/lib/ReactViews/Map/BottomBar/Credits/Credit.type.ts similarity index 100% rename from lib/ReactViews/Credits/Credit.type.ts rename to lib/ReactViews/Map/BottomBar/Credits/Credit.type.ts diff --git a/lib/ReactViews/Credits/Credits.tsx b/lib/ReactViews/Map/BottomBar/Credits/Credits.tsx similarity index 100% rename from lib/ReactViews/Credits/Credits.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Credits.tsx diff --git a/lib/ReactViews/Credits/CreditsContainer.tsx b/lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx similarity index 62% rename from lib/ReactViews/Credits/CreditsContainer.tsx rename to lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx index 3bc865a84bc..3fd049e8c8e 100644 --- a/lib/ReactViews/Credits/CreditsContainer.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx @@ -1,19 +1,12 @@ import styled from "styled-components"; -import Box from "../../Styled/Box"; +import Box from "../../../../Styled/Box"; export const CreditsContainer = styled(Box).attrs(() => ({ - fullWidth: true, styledHeight: "30px", styledMaxHeight: "30px", verticalCenter: true, - gap: true, - position: "absolute" + gap: true }))` - z-index: 0; - bottom: 0; - background: linear-gradient(180deg, #000000 0%, #000000 100%); - font-size: 0.7rem; - opacity: 0.75; a { text-decoration: underline; cursor: pointer; @@ -21,7 +14,6 @@ export const CreditsContainer = styled(Box).attrs(() => ({ display: flex; align-items: center; } - img { height: 24px; } diff --git a/lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx b/lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx similarity index 86% rename from lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx rename to lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx index 0e6be655b42..b5b1856e5ca 100644 --- a/lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx @@ -3,13 +3,13 @@ import React, { FC } from "react"; import ReactDOM from "react-dom"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; -import Box from "../../../Styled/Box"; -import { Li } from "../../../Styled/List"; -import Spacing from "../../../Styled/Spacing"; -import Text from "../../../Styled/Text"; -import parseCustomHtmlToReact from "../../Custom/parseCustomHtmlToReact"; -import CloseButton from "../../Generic/CloseButton"; -import { PrefaceBox } from "../../Generic/PrefaceBox"; +import Box from "../../../../../Styled/Box"; +import { Li } from "../../../../../Styled/List"; +import Spacing from "../../../../../Styled/Spacing"; +import Text from "../../../../../Styled/Text"; +import parseCustomHtmlToReact from "../../../../Custom/parseCustomHtmlToReact"; +import CloseButton from "../../../../Generic/CloseButton"; +import { PrefaceBox } from "../../../../Generic/PrefaceBox"; interface IDataAttributionModalProps { closeModal: () => void; @@ -20,7 +20,6 @@ const AttributionText = styled(Text).attrs(() => ({ medium: true }))` a { color: ${(props) => props.theme.textDark}; text-decoration: underline; - img { height: 19px; vertical-align: middle; diff --git a/lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx b/lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx similarity index 75% rename from lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx rename to lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx index 9ba2b6be382..7f0cffb0b18 100644 --- a/lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx @@ -1,8 +1,8 @@ import React, { FC } from "react"; import CreditDisplay from "terriajs-cesium/Source/Scene/CreditDisplay"; -import GlobeOrMap from "../../../Models/GlobeOrMap"; -import Leaflet from "../../../Models/Leaflet"; -import parseCustomHtmlToReact from "../../Custom/parseCustomHtmlToReact"; +import GlobeOrMap from "../../../../Models/GlobeOrMap"; +import Leaflet from "../../../../Models/Leaflet"; +import parseCustomHtmlToReact from "../../../Custom/parseCustomHtmlToReact"; interface IMapCreditLogoProps { currentViewer: GlobeOrMap; diff --git a/lib/ReactViews/Credits/MapCredits/MapCredits.tsx b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx similarity index 84% rename from lib/ReactViews/Credits/MapCredits/MapCredits.tsx rename to lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx index 404abdeeb8b..05a8a30a118 100644 --- a/lib/ReactViews/Credits/MapCredits/MapCredits.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx @@ -2,13 +2,13 @@ import { reaction } from "mobx"; import { observer } from "mobx-react"; import React, { FC, useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import GlobeOrMap from "../../../Models/GlobeOrMap"; -import { ICredit } from "../Credit.type"; -import { Credits } from "../Credits"; -import { CreditsContainer } from "../CreditsContainer"; -import { DataAttributionModal } from "../DataAttribution/DataAttributionModal"; -import { Spacer } from "../Spacer"; -import { TerriaLogo } from "../TerriaLogo"; +import GlobeOrMap from "../../../../Models/GlobeOrMap"; +import { ICredit } from "./Credit.type"; +import { Credits } from "./Credits"; +import { CreditsContainer } from "./CreditsContainer"; +import { DataAttributionModal } from "./DataAttribution/DataAttributionModal"; +import { Spacer } from "./Spacer"; +import { TerriaLogo } from "./TerriaLogo"; import { MapCreditLogo } from "./MapCreditLogo"; interface IMapCreditsProps { diff --git a/lib/ReactViews/Credits/Spacer.tsx b/lib/ReactViews/Map/BottomBar/Credits/Spacer.tsx similarity index 100% rename from lib/ReactViews/Credits/Spacer.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Spacer.tsx diff --git a/lib/ReactViews/Credits/TerriaLogo.tsx b/lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx similarity index 71% rename from lib/ReactViews/Credits/TerriaLogo.tsx rename to lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx index ab56a9046ed..fd035fd8688 100644 --- a/lib/ReactViews/Credits/TerriaLogo.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx @@ -1,7 +1,7 @@ import React, { FC } from "react"; -import Box from "../../Styled/Box"; +import Box from "../../../../Styled/Box"; -const logo = require("../../../wwwroot/images/terria-watermark.svg"); +const logo = require("../../../../../wwwroot/images/terria-watermark.svg"); export const TerriaLogo: FC = () => { return ( diff --git a/lib/ReactViews/Map/BottomBar/Credits/index.ts b/lib/ReactViews/Map/BottomBar/Credits/index.ts new file mode 100644 index 00000000000..ebd9ea095ca --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/Credits/index.ts @@ -0,0 +1,2 @@ +export { ICredit } from "./Credit.type"; +export { MapCredits } from "./MapCredits"; diff --git a/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx new file mode 100644 index 00000000000..eb17467a7d8 --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx @@ -0,0 +1,211 @@ +"use strict"; +import L from "leaflet"; +import { runInAction } from "mobx"; +import { observer } from "mobx-react"; +import React, { FC, useEffect, useState, memo } from "react"; +import { useTheme } from "styled-components"; +import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; +import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic"; +import CesiumEvent from "terriajs-cesium/Source/Core/Event"; +import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; +import Scene from "terriajs-cesium/Source/Scene/Scene"; +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 +]; + +interface IDistanceLegendProps { + scale?: number; + isPrintMode?: boolean; +} + +export const DistanceLegend: FC = observer( + ({ scale = 1, isPrintMode = false }) => { + const [distanceLabel, setDistanceLabel] = useState(); + const [barWidth, setBarWidth] = useState(0); + + const { terria } = useViewState(); + const theme = useTheme(); + + let removeUpdateSubscription: + | CesiumEvent.RemoveCallback + | (() => void) + | undefined; + + useEffect(() => { + const viewerSubscriptions: CesiumEvent.RemoveCallback[] = []; + + removeUpdateSubscription = addUpdateSubscription(); + + return () => { + if (removeUpdateSubscription) { + removeUpdateSubscription(); + } + viewerSubscriptions.forEach((clear) => clear()); + }; + }, [terria.cesium, terria.leaflet]); + + const addUpdateSubscription = (): + | CesiumEvent.RemoveCallback + | (() => void) + | undefined => { + if (isDefined(terria.cesium)) { + const scene = terria.cesium.scene; + let removeUpdateSubscription: CesiumEvent.RemoveCallback | undefined = + scene.postRender.addEventListener(() => { + updateDistanceLegendCesium(scene); + if (isPrintMode) { + removeUpdateSubscription?.(); + removeUpdateSubscription = undefined; + } + }); + return removeUpdateSubscription; + } else if (isDefined(terria.leaflet)) { + const map = terria.leaflet.map; + let removeUpdateSubscription: (() => void) | undefined = 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: Scene) => { + const now = getTimestamp(); + + // 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: L.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-ignore + 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 ? ( + + + {distanceLabel} + +
+ + ) : null; + } +); diff --git a/lib/ReactViews/Map/BottomBar/LocationBar.tsx b/lib/ReactViews/Map/BottomBar/LocationBar.tsx new file mode 100644 index 00000000000..a8b99e2133c --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/LocationBar.tsx @@ -0,0 +1,114 @@ +import React from "react"; +import { observer } from "mobx-react"; +import { FC, RefObject, useEffect, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import styled, { useTheme } from "styled-components"; +import MouseCoords from "../../../ReactViewModels/MouseCoords"; +import Box from "../../../Styled/Box"; +import { RawButton } from "../../../Styled/Button"; + +interface ILocationBarProps { + mouseCoords: MouseCoords; +} + +const Section = styled(Box).attrs({ + paddedHorizontally: true +})``; + +const StyledText = styled.span` + font-family: ${(props) => props.theme.fontMono}; + color: ${(props) => props.theme.textLight}; + white-space: nowrap; + font-size: 0.7rem; + padding: 0 5px 0 5px; +`; + +const setInnerText = (ref: RefObject, value: string) => { + if (ref.current) ref.current.innerText = value; +}; + +export const LocationBar: FC = observer( + ({ mouseCoords }) => { + const theme = useTheme(); + const { t } = useTranslation(); + + const elevationRef = useRef(null); + const longitudeRef = useRef(null); + const latitudeRef = useRef(null); + const utmZoneRef = useRef(null); + const eastRef = useRef(null); + const northRef = useRef(null); + + useEffect(() => { + const disposer = mouseCoords.updateEvent.addEventListener(() => { + setInnerText(elevationRef, mouseCoords.elevation ?? ""); + setInnerText(longitudeRef, mouseCoords.longitude ?? ""); + setInnerText(latitudeRef, mouseCoords.latitude ?? ""); + setInnerText(utmZoneRef, mouseCoords.utmZone ?? ""); + setInnerText(eastRef, mouseCoords.east ?? ""); + setInnerText(northRef, mouseCoords.north ?? ""); + }); + return disposer; + }); + + return ( + + + {!mouseCoords.useProjection ? ( + <> +
+ {t("legend.lat")} + + {mouseCoords.latitude} + +
+
+ {t("legend.lon")} + + {mouseCoords.longitude} + +
+ + ) : ( + <> +
+ {t("legend.zone")} + {mouseCoords.utmZone} +
+
+ {t("legend.e")} + {mouseCoords.east} +
+
+ {t("legend.n")} + {mouseCoords.north} +
+ + )} +
+ {t("legend.elev")} + {mouseCoords.elevation} +
+
+
+ ); + } +); diff --git a/lib/ReactViews/Map/BottomBar/index.ts b/lib/ReactViews/Map/BottomBar/index.ts new file mode 100644 index 00000000000..c8b81e2ff08 --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/index.ts @@ -0,0 +1 @@ +export { BottomBar } from "./BottomBar"; diff --git a/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx b/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx index 053feec01d1..f6fdd77d369 100644 --- a/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx +++ b/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { FC } from "react"; import { useTranslation } from "react-i18next"; import ViewState from "../../../ReactViewModels/ViewState"; @@ -10,47 +10,43 @@ import MapDataCount from "../../BottomDock/MapDataCount"; import Terria from "../../../Models/Terria"; import MapIconButton from "../../MapIconButton/MapIconButton"; import defined from "terriajs-cesium/Source/Core/defined"; - -interface Props { - terria: Terria; - viewState: ViewState; -} +import { useViewState } from "../../Context"; const BottomLeftContainer = styled(Box)` position: absolute; bottom: 40px; - @media (max-width: ${(props) => props.theme.mobile}px) { bottom: 35px; } `; -const shouldShowPlayStoryButton = (props: Props) => - props.terria.configParameters.storyEnabled && - defined(props.terria.stories) && - props.terria.stories.length > 0 && - props.viewState.useSmallScreenInterface; +const shouldShowPlayStoryButton = (viewState: ViewState) => + viewState.terria.configParameters.storyEnabled && + defined(viewState.terria.stories) && + viewState.terria.stories.length > 0 && + viewState.useSmallScreenInterface; -const BottomLeftBar = (props: Props) => { +const BottomLeftBar: FC = () => { const { t } = useTranslation(); const theme = useTheme(); + const viewState = useViewState(); const isNotificationActive = - props.terria.notificationState.currentNotification; + viewState.terria.notificationState.currentNotification; return ( - {shouldShowPlayStoryButton(props) ? ( + {shouldShowPlayStoryButton(viewState) ? ( } - onClick={() => props.viewState.runStories()} + onClick={() => viewState.runStories()} primary={!isNotificationActive} > {t("story.playStory")} diff --git a/lib/ReactViews/Map/HelpButton/help-button.scss b/lib/ReactViews/Map/HelpButton/help-button.scss deleted file mode 100644 index c89132566d1..00000000000 --- a/lib/ReactViews/Map/HelpButton/help-button.scss +++ /dev/null @@ -1,4 +0,0 @@ -.helpBtn { - composes: btn from "../../../Sass/common/_buttons.scss"; - composes: btn--map from "../../../Sass/common/_buttons.scss"; -} diff --git a/lib/ReactViews/Map/Legend/DistanceLegend.jsx b/lib/ReactViews/Map/Legend/DistanceLegend.jsx deleted file mode 100644 index ec367981f3e..00000000000 --- a/lib/ReactViews/Map/Legend/DistanceLegend.jsx +++ /dev/null @@ -1,202 +0,0 @@ -"use strict"; -import React from "react"; -import PropTypes from "prop-types"; -import L from "leaflet"; -import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; -import defined from "terriajs-cesium/Source/Core/defined"; -import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic"; -import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; -import Styles from "./legend.scss"; -import { observer, disposeOnUnmount } from "mobx-react"; -import { autorun, runInAction } from "mobx"; - -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 -]; - -@observer -class DistanceLegend extends React.Component { - constructor(props) { - super(props); - this.state = { - distanceLabel: undefined, - barWidth: 0 - }; - } - static displayName = "DistanceLegend"; - static propTypes = { - terria: PropTypes.object, - scale: PropTypes.number, - isPrintMode: PropTypes.bool - }; - - /* eslint-disable-next-line camelcase */ - UNSAFE_componentWillMount() { - this.viewerSubscriptions = []; - this.removeUpdateSubscription = undefined; - - this._lastLegendUpdate = undefined; - this.viewerSubscriptions.push( - this.props.terria.mainViewer.beforeViewerChanged.addEventListener(() => { - if (defined(this.removeUpdateSubscription)) { - this.removeUpdateSubscription(); - this.removeUpdateSubscription = undefined; - } - }) - ); - disposeOnUnmount( - this, - autorun(() => this.addUpdateSubscription()) - ); - } - - componentWillUnmount() { - this.removeUpdateSubscription && this.removeUpdateSubscription(); - this.viewerSubscriptions.forEach((remove) => remove()); - } - - addUpdateSubscription() { - const that = this; - if (defined(this.props.terria.cesium)) { - const scene = this.props.terria.cesium.scene; - this.removeUpdateSubscription = scene.postRender.addEventListener(() => { - this.updateDistanceLegendCesium(scene); - if (this.props.isPrintMode) { - this.removeUpdateSubscription(); - this.removeUpdateSubscription = null; - } - }); - } else if (defined(this.props.terria.leaflet)) { - const map = this.props.terria.leaflet.map; - - const potentialChangeCallback = function potentialChangeCallback() { - that.updateDistanceLegendLeaflet(map); - }; - if (!this.props.isPrintMode) { - that.removeUpdateSubscription = function () { - map.off("zoomend", potentialChangeCallback); - map.off("moveend", potentialChangeCallback); - }; - - map.on("zoomend", potentialChangeCallback); - map.on("moveend", potentialChangeCallback); - } - - that.updateDistanceLegendLeaflet(map); - } - } - - updateDistanceLegendCesium(scene) { - const now = getTimestamp(); - if (now < this._lastLegendUpdate + 250) { - return; - } - - this._lastLegendUpdate = now; - - // 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; - const leftPosition = globe.pick(left, scene); - const rightPosition = globe.pick(right, scene); - - if (!defined(leftPosition) || !defined(rightPosition)) { - this.setState({ - barWidth: undefined, - distanceLabel: undefined - }); - return; - } - - const leftCartographic = - globe.ellipsoid.cartesianToCartographic(leftPosition); - const rightCartographic = - globe.ellipsoid.cartesianToCartographic(rightPosition); - - geodesic.setEndPoints(leftCartographic, rightCartographic); - const pixelDistance = geodesic.surfaceDistance; - runInAction(() => (this.props.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; !defined(distance) && i >= 0; --i) { - if (distances[i] / pixelDistance < maxBarWidth) { - distance = distances[i]; - } - } - - if (defined(distance)) { - let label; - if (distance >= 1000) { - label = (distance / 1000).toString() + " km"; - } else { - label = distance.toString() + " m"; - } - - this.setState({ - barWidth: ((distance / pixelDistance) * this.props.scale) | 0, - distanceLabel: label - }); - } else { - this.setState({ - barWidth: undefined, - distanceLabel: undefined - }); - } - } - - updateDistanceLegendLeaflet(map) { - const halfHeight = map.getSize().y / 2; - const maxPixelWidth = 100; - const maxMeters = map - .containerPointToLatLng([0, halfHeight]) - .distanceTo(map.containerPointToLatLng([maxPixelWidth, halfHeight])); - - runInAction(() => (this.props.terria.mainViewer.scale = maxMeters / 100)); - - const meters = L.control.scale()._getRoundNum(maxMeters); - const label = meters < 1000 ? meters + " m" : meters / 1000 + " km"; - - this.setState({ - barWidth: (meters / maxMeters) * maxPixelWidth * this.props.scale, - distanceLabel: label - }); - } - - render() { - const barStyle = { - width: this.state.barWidth + "px", - left: 5 + (125 - this.state.barWidth) / 2 + "px", - height: "2px" - }; - - const distanceLabel = this.state.distanceLabel ? ( -
- -
-
- ) : null; - - return distanceLabel; - } -} -DistanceLegend.defaultProps = { - scale: 1, - isPrintMode: false -}; - -export default DistanceLegend; diff --git a/lib/ReactViews/Map/Legend/LocationBar.tsx b/lib/ReactViews/Map/Legend/LocationBar.tsx deleted file mode 100644 index b7b0431059d..00000000000 --- a/lib/ReactViews/Map/Legend/LocationBar.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import classNames from "classnames"; -import { observer } from "mobx-react"; -import React, { RefObject, useEffect, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import styled from "styled-components"; -import Terria from "../../../Models/Terria"; -import MouseCoords from "../../../ReactViewModels/MouseCoords"; -import Styles from "./legend.scss"; - -interface PropsType { - terria: Terria; - showUtmZone: boolean; - mouseCoords: MouseCoords; -} - -const LocationBar: React.FC = observer(({ mouseCoords }) => { - const { t } = useTranslation(); - const elevationRef = useRef(null); - const longitudeRef = useRef(null); - const latitudeRef = useRef(null); - const utmZoneRef = useRef(null); - const eastRef = useRef(null); - const northRef = useRef(null); - - useEffect(() => { - const disposer = mouseCoords.updateEvent.addEventListener(() => { - setInnerText(elevationRef, mouseCoords.elevation ?? ""); - setInnerText(longitudeRef, mouseCoords.longitude ?? ""); - setInnerText(latitudeRef, mouseCoords.latitude ?? ""); - setInnerText(utmZoneRef, mouseCoords.utmZone ?? ""); - setInnerText(eastRef, mouseCoords.east ?? ""); - setInnerText(northRef, mouseCoords.north ?? ""); - }); - return disposer; - }); - - return ( - mouseCoords.toggleUseProjection()} - > - {!mouseCoords.useProjection && ( - <> -
- {t("legend.lat")} - {mouseCoords.latitude} -
-
- {t("legend.lon")} - {mouseCoords.longitude} -
- - )} - {mouseCoords.useProjection && ( - <> -
- {t("legend.zone")} - {mouseCoords.utmZone} -
-
- {t("legend.e")} - {mouseCoords.east} -
-
- {t("legend.n")} - {mouseCoords.north} -
- - )} -
- {t("legend.elev")} - {mouseCoords.elevation} -
-
- ); -}); - -function setInnerText(ref: RefObject, value: string) { - if (ref.current) ref.current.innerText = value; -} - -const LocationButton = styled.button` - &:hover { - background: ${(p) => p.theme.colorPrimary}; - } -`; - -export default LocationBar; diff --git a/lib/ReactViews/Map/Legend/legend.scss b/lib/ReactViews/Map/Legend/legend.scss deleted file mode 100644 index 58110a76b6e..00000000000 --- a/lib/ReactViews/Map/Legend/legend.scss +++ /dev/null @@ -1,75 +0,0 @@ -@import "~terriajs-variables"; -@import "../../../Sass/common/mixins"; - -$distance-bg: rgba($dark, 0.9); - -.baseLegend { - box-sizing: border-box; - font-family: $font-base; - float: left; - background-color: #fff; - color: $text-dark; - padding: $padding-small $padding-small; - font-size: $font-size-mid-mini; - text-align: center; - line-height: 1; - border: 0; - outline: 0; - font-family: $font-mono; - max-height: 21px; - margin-top: $padding-mini; - &:hover { - background: $faint-bg; - } - - .bar { - background: #fff; - margin: 0 auto; - display: block; - @include transition(all 0.5s ease-in-out); - } -} - -.locationBar, -.distanceLegend { - composes: baseLegend; - // Adjust colors to match btn--map. - background-color: unset; - margin-bottom: $padding-mini; - color: $text-light; - &:hover { - // background: $color-primary; - } - // - margin-right: $padding-small; - span { - padding: 0 $padding-small; - } - - li, - div { - display: inline-block; - padding: 0 $padding-small; - text-align: left; - } - - .section-long { - width: 130px; - } - - .section { - width: 112px; - } - - .section-short { - width: 70px; - } -} - -.distanceLegend { - &:hover { - background: $charcoal-grey; - } - text-align: center; - width: 110px; -} diff --git a/lib/ReactViews/Map/Legend/legend.scss.d.ts b/lib/ReactViews/Map/Legend/legend.scss.d.ts deleted file mode 100644 index 2216fd3b3ba..00000000000 --- a/lib/ReactViews/Map/Legend/legend.scss.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'bar': string; - 'baseLegend': string; - 'distanceLegend': string; - 'locationBar': string; - 'section': string; - 'section-long': string; - 'section-short': string; - 'sectionLong': string; - 'sectionShort': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/MapColumn.tsx b/lib/ReactViews/Map/MapColumn.tsx new file mode 100644 index 00000000000..eb33ebc28c8 --- /dev/null +++ b/lib/ReactViews/Map/MapColumn.tsx @@ -0,0 +1,140 @@ +import { observer } from "mobx-react"; +import React, { FC } from "react"; +import { useTranslation } from "react-i18next"; +import Box from "../../Styled/Box"; +import ActionBarPortal from "../ActionBar/ActionBarPortal"; +import BottomDock from "../BottomDock/BottomDock"; +import { useViewState } from "../Context"; +import Loader from "../Loader"; +import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; +import { BottomBar } from "./BottomBar"; +import BottomLeftBar from "./BottomLeftBar/BottomLeftBar"; +import { MapNavigation } from "./MapNavigation"; +import MenuBar from "./MenuBar/MenuBar"; +import { ProgressBar } from "./ProgressBar"; +import { TerriaViewerWrapper } from "./TerriaViewerWrapper"; +import Toast from "./Toast"; + +interface IMapColumnProps { + customFeedbacks: any; + animationDuration: number; + customElements: any; +} + +/** + * Right-hand column that contains the map, controls that sit over the map and sometimes the bottom dock containing + * the timeline and charts. + */ +export const MapColumn: FC = observer( + ({ customFeedbacks, customElements, animationDuration }) => { + const viewState = useViewState(); + const { t } = useTranslation(); + + return ( + + +
+ +
+ {!viewState.hideMapUi && ( +
+ + +
+ )} + + + + {!viewState.hideMapUi && ( + <> + + + + + + + + + + + + {viewState.terria.configParameters.printDisclaimer && ( + + {viewState.terria.configParameters.printDisclaimer.text} + + )} + + )} +
+
+ {!viewState.hideMapUi && ( + + )} +
+
+ ); + } +); + +export default MapColumn; diff --git a/lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx b/lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx similarity index 84% rename from lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx rename to lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx index cd99a45382f..57b1ef8c648 100644 --- a/lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx +++ b/lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx @@ -3,16 +3,16 @@ import { observer } from "mobx-react"; import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; import styled, { useTheme } from "styled-components"; -import { applyTranslationIfExists } from "../../../../Language/languageHelpers"; -import Box, { BoxSpan } from "../../../../Styled/Box"; -import { StyledIcon } from "../../../../Styled/Icon"; -import Spacing from "../../../../Styled/Spacing"; -import Text from "../../../../Styled/Text"; -import { IMapNavigationItem } from "../../../../ViewModels/MapNavigation/MapNavigationModel"; -import CloseButton from "../../../Generic/CloseButton"; -import { PrefaceBox } from "../../../Generic/PrefaceBox"; -import { useViewState } from "../../../StandardUserInterface/ViewStateContext"; -import { filterViewerAndScreenSize } from "../MapNavigation"; +import { applyTranslationIfExists } from "../../../Language/languageHelpers"; +import Box, { BoxSpan } from "../../../Styled/Box"; +import { StyledIcon } from "../../../Styled/Icon"; +import Spacing from "../../../Styled/Spacing"; +import Text from "../../../Styled/Text"; +import { IMapNavigationItem } from "../../../ViewModels/MapNavigation/MapNavigationModel"; +import { useViewState } from "../../Context"; +import CloseButton from "../../Generic/CloseButton"; +import { PrefaceBox } from "../../Generic/PrefaceBox"; +import { filterViewerAndScreenSize } from "./filterViewerAndScreenSize"; interface PropTypes { items: IMapNavigationItem[]; @@ -128,7 +128,7 @@ const CollapsedNavigationPanel: React.FC = observer( ); const CollapsedNavigationDisplayName = "CollapsedNavigation"; -const CollapsedNavigation: React.FC = observer(() => { +export const CollapsedNavigation: React.FC = observer(() => { const viewState = useViewState(); useEffect(() => autorun(() => { @@ -163,5 +163,3 @@ const CollapsedNavigation: React.FC = observer(() => { ); }); - -export default CollapsedNavigation; diff --git a/lib/ReactViews/Map/Navigation/Items/AugmentedVirtualityTool.tsx b/lib/ReactViews/Map/MapNavigation/Items/AugmentedVirtualityTool.tsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/AugmentedVirtualityTool.tsx rename to lib/ReactViews/Map/MapNavigation/Items/AugmentedVirtualityTool.tsx diff --git a/lib/ReactViews/Map/Navigation/Items/CatalogShortcut.jsx b/lib/ReactViews/Map/MapNavigation/Items/CatalogShortcut.jsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/CatalogShortcut.jsx rename to lib/ReactViews/Map/MapNavigation/Items/CatalogShortcut.jsx diff --git a/lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx b/lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx similarity index 65% rename from lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx rename to lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx index 719b03526d0..377e116533d 100644 --- a/lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx @@ -1,15 +1,12 @@ -import React from "react"; -import { withTranslation, WithTranslation } from "react-i18next"; -import ViewState from "../../../../ReactViewModels/ViewState"; +import React, { FC } from "react"; +import { useTranslation } from "react-i18next"; import Icon from "../../../../Styled/Icon"; +import { useViewState } from "../../../Context"; import MapIconButton from "../../../MapIconButton/MapIconButton"; -interface PropsType extends WithTranslation { - viewState: ViewState; - t: any; -} - -function CloseToolButton({ viewState, t }: PropsType) { +export const CloseToolButton: FC = () => { + const { t } = useTranslation(); + const viewState = useViewState(); const closeText = t("tool.closeButtonTitle", { toolName: viewState.currentTool?.toolName }); @@ -31,6 +28,4 @@ function CloseToolButton({ viewState, t }: PropsType) { {closeText} ); -} - -export default withTranslation()(CloseToolButton); +}; diff --git a/lib/ReactViews/Map/Navigation/Items/Compass.tsx b/lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx similarity index 97% rename from lib/ReactViews/Map/Navigation/Items/Compass.tsx rename to lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx index 48981d45895..a989f007286 100644 --- a/lib/ReactViews/Map/Navigation/Items/Compass.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx @@ -10,7 +10,8 @@ */ // import { TFunction } from "i18next"; -import { computed, runInAction, when, makeObservable } from "mobx"; +import { computed, runInAction, when } from "mobx"; +import debounce from "lodash-es/debounce"; import React from "react"; import { WithTranslation, withTranslation } from "react-i18next"; import styled, { DefaultTheme, withTheme } from "styled-components"; @@ -22,17 +23,16 @@ import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; import CesiumMath from "terriajs-cesium/Source/Core/Math"; import Matrix4 from "terriajs-cesium/Source/Core/Matrix4"; import Ray from "terriajs-cesium/Source/Core/Ray"; -import Transforms from "terriajs-cesium/Source/Core/Transforms"; -import isDefined from "../../../../Core/isDefined"; -import Terria from "../../../../Models/Terria"; -import ViewState from "../../../../ReactViewModels/ViewState"; -import Box from "../../../../Styled/Box"; -import Icon, { StyledIcon } from "../../../../Styled/Icon"; -import GyroscopeGuidance from "../../../GyroscopeGuidance/GyroscopeGuidance"; -import { withTerriaRef } from "../../../HOCs/withTerriaRef"; -import FadeIn from "../../../Transitions/FadeIn/FadeIn"; -import debounce from "lodash-es/debounce"; import Scene from "terriajs-cesium/Source/Scene/Scene"; +import Transforms from "terriajs-cesium/Source/Core/Transforms"; +import isDefined from "../../../../../Core/isDefined"; +import Terria from "../../../../../Models/Terria"; +import ViewState from "../../../../../ReactViewModels/ViewState"; +import Box from "../../../../../Styled/Box"; +import Icon, { StyledIcon } from "../../../../../Styled/Icon"; +import { GyroscopeGuidance } from "./GyroscopeGuidance"; +import { withTerriaRef } from "../../../../HOCs/withTerriaRef"; +import FadeIn from "../../../../Transitions/FadeIn/FadeIn"; const CameraFlightPath = require("terriajs-cesium/Source/Scene/CameraFlightPath").default; @@ -178,7 +178,6 @@ class Compass extends React.PureComponent { */ constructor(props: PropTypes) { super(props); - makeObservable(this); this.state = { orbitCursorAngle: 0, heading: 0.0, @@ -385,7 +384,7 @@ class Compass extends React.PureComponent { this.setState({ active: true })} onMouseOut={() => { diff --git a/lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx similarity index 91% rename from lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx rename to lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx index 1c985776010..b1ff9cf0ff5 100644 --- a/lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx @@ -3,15 +3,15 @@ import styled, { css } from "styled-components"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -import Icon from "../../Styled/Icon"; -import Box from "../../Styled/Box"; -import { TextSpan } from "../../Styled/Text"; -import { RawButton } from "../../Styled/Button"; -import Spacing from "../../Styled/Spacing"; -import MapIconButton from "../MapIconButton/MapIconButton"; +import Icon from "../../../../../Styled/Icon"; +import Box from "../../../../../Styled/Box"; +import { TextSpan } from "../../../../../Styled/Text"; +import { RawButton } from "../../../../../Styled/Button"; +import Spacing from "../../../../../Styled/Spacing"; +import MapIconButton from "../../../../MapIconButton/MapIconButton"; // import MenuPanel from "../StandardUserInterface/customizable/MenuPanel"; -import CleanDropdownPanel from "../CleanDropdownPanel/CleanDropdownPanel"; -import { COMPASS_LOCAL_PROPERTY_KEY } from "../Map/Navigation/Items/Compass"; +import CleanDropdownPanel from "../../../../CleanDropdownPanel/CleanDropdownPanel"; +import { COMPASS_LOCAL_PROPERTY_KEY } from "./Compass"; GyroscopeGuidance.propTypes = { viewState: PropTypes.object.isRequired, @@ -129,7 +129,7 @@ GyroscopeGuidancePanel.propTypes = { onClose: PropTypes.func.isRequired }; -export default function GyroscopeGuidance(props) { +export function GyroscopeGuidance(props) { const [controlPanelOpen, setControlPanelOpen] = useState(false); const controlsMapIcon = useRef(); const { t } = useTranslation(); diff --git a/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts b/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts new file mode 100644 index 00000000000..8c4f56534da --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts @@ -0,0 +1,4 @@ +import Compass from "./Compass"; + +export { COMPASS_TOOL_ID } from "./Compass"; +export { Compass }; diff --git a/lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx b/lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx similarity index 94% rename from lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx rename to lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx index 00dd022ea15..7cf03c5e460 100644 --- a/lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx @@ -19,7 +19,7 @@ interface PropTypes { } @observer -class MapNavigationItem extends React.Component { +class MapNavigationItemBase extends React.Component { constructor(props: PropTypes) { super(props); } @@ -73,4 +73,4 @@ export const Control = styled(Box).attrs({ text-align: center; `; -export default withTranslation()(MapNavigationItem); +export const MapNavigationItem = withTranslation()(MapNavigationItemBase); diff --git a/lib/ReactViews/Map/Navigation/Items/MeasureTool.ts b/lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts similarity index 99% rename from lib/ReactViews/Map/Navigation/Items/MeasureTool.ts rename to lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts index 65beee07da7..d84a06c0ce4 100644 --- a/lib/ReactViews/Map/Navigation/Items/MeasureTool.ts +++ b/lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts @@ -21,7 +21,7 @@ interface MeasureToolOptions { onClose(): void; } -export default class MeasureTool extends MapNavigationItemController { +export class MeasureTool extends MapNavigationItemController { static id = "measure-tool"; static displayName = "MeasureTool"; diff --git a/lib/ReactViews/Map/Navigation/Items/MyLocation.ts b/lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts similarity index 98% rename from lib/ReactViews/Map/Navigation/Items/MyLocation.ts rename to lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts index 87bec7836d6..b2245d98a4e 100644 --- a/lib/ReactViews/Map/Navigation/Items/MyLocation.ts +++ b/lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts @@ -19,7 +19,7 @@ interface PropTypes { terria: Terria; } -class MyLocation extends MapNavigationItemController { +export class MyLocation extends MapNavigationItemController { static id = "my-location"; static displayName = "MyLocation"; readonly terria: Terria; @@ -200,5 +200,3 @@ class MyLocation extends MapNavigationItemController { } } } - -export default MyLocation; diff --git a/lib/ReactViews/Map/Navigation/Items/ToggleSplitterTool.ts b/lib/ReactViews/Map/MapNavigation/Items/ToggleSplitterTool.ts similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/ToggleSplitterTool.ts rename to lib/ReactViews/Map/MapNavigation/Items/ToggleSplitterTool.ts diff --git a/lib/ReactViews/Map/Navigation/Items/ToolButton.tsx b/lib/ReactViews/Map/MapNavigation/Items/ToolButton.tsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/ToolButton.tsx rename to lib/ReactViews/Map/MapNavigation/Items/ToolButton.tsx diff --git a/lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx similarity index 97% rename from lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx rename to lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx index 429a76d15af..61aa2971de0 100644 --- a/lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx @@ -17,7 +17,7 @@ import Box from "../../../../Styled/Box"; import { RawButton } from "../../../../Styled/Button"; import Icon, { GLYPHS } from "../../../../Styled/Icon"; import Ul, { Li } from "../../../../Styled/List"; -import Terria from "./../../../../Models/Terria"; +import Terria from "../../../../Models/Terria"; const Tween = require("terriajs-cesium/Source/ThirdParty/Tween").default; @@ -29,7 +29,7 @@ interface PropTypes extends WithTranslation { export const ZOOM_CONTROL_ID = "zoom"; -class ZoomControl extends React.Component { +class ZoomControlBase extends React.Component { static displayName = "ZoomControl"; constructor(props: PropTypes) { @@ -236,10 +236,9 @@ const StyledZoomControl = styled(Box).attrs((props) => ({ width: 20px; fill: ${(props) => props.theme.darkWithOverlay}; } - ${Li} { margin: 5px 0; } `; -export default withTranslation()(withTheme(ZoomControl)); +export const ZoomControl = withTranslation()(withTheme(ZoomControlBase)); diff --git a/lib/ReactViews/Map/MapNavigation/Items/index.ts b/lib/ReactViews/Map/MapNavigation/Items/index.ts new file mode 100644 index 00000000000..7d28299b240 --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/Items/index.ts @@ -0,0 +1,14 @@ +export { + AR_TOOL_ID, + AugmentedVirtualityController, + AugmentedVirtualityHoverController, + AugmentedVirtualityRealign, + AugmentedVirtualityRealignController +} from "./AugmentedVirtualityTool"; +export { CloseToolButton } from "./CloseToolButton"; +export * from "./Compass"; +export { Control, MapNavigationItem } from "./MapNavigationItem"; +export { MeasureTool } from "./MeasureTool"; +export { MyLocation } from "./MyLocation"; +export { ToggleSplitterController } from "./ToggleSplitterTool"; +export { ZoomControl, ZOOM_CONTROL_ID } from "./ZoomControl"; diff --git a/lib/ReactViews/Map/Navigation/MapNavigation.tsx b/lib/ReactViews/Map/MapNavigation/MapNavigation.tsx similarity index 90% rename from lib/ReactViews/Map/Navigation/MapNavigation.tsx rename to lib/ReactViews/Map/MapNavigation/MapNavigation.tsx index e1be09ea9e3..5f6ef8cf951 100644 --- a/lib/ReactViews/Map/Navigation/MapNavigation.tsx +++ b/lib/ReactViews/Map/MapNavigation/MapNavigation.tsx @@ -13,7 +13,6 @@ import { observer } from "mobx-react"; import React from "react"; import { WithTranslation, withTranslation } from "react-i18next"; import styled, { DefaultTheme, withTheme } from "styled-components"; -import isDefined from "../../../Core/isDefined"; import ViewState from "../../../ReactViewModels/ViewState"; import Box from "../../../Styled/Box"; import Icon, { GLYPHS } from "../../../Styled/Icon"; @@ -23,9 +22,9 @@ import MapNavigationModel, { } from "../../../ViewModels/MapNavigation/MapNavigationModel"; import withControlledVisibility from "../../HOCs/withControlledVisibility"; import MapIconButton from "../../MapIconButton/MapIconButton"; -import MapNavigationItem, { Control } from "./Items/MapNavigationItem"; +import { filterViewerAndScreenSize } from "./filterViewerAndScreenSize"; +import { Control, MapNavigationItem } from "./Items"; import { registerMapNavigations } from "./registerMapNavigations"; -import { ScreenSize } from "../../../ViewModels/CompositeBar/CompositeBarModel"; const OVERFLOW_ACTION_SIZE = 42; @@ -56,11 +55,9 @@ const StyledMapNavigation = styled.div` } } pointer-events: none; - button { pointer-events: auto; } - ${(p) => p.trainerBarVisible && ` @@ -90,7 +87,7 @@ enum Orientation { } @observer -class MapNavigation extends React.Component { +class MapNavigationBase extends React.Component { static displayName = "MapNavigation"; private navigationRef = React.createRef(); private readonly resizeListener: () => any; @@ -330,27 +327,6 @@ class MapNavigation extends React.Component { } } -export default withTranslation()( - withTheme(withControlledVisibility(MapNavigation)) +export const MapNavigation = withTranslation()( + withTheme(withControlledVisibility(MapNavigationBase)) ); - -export function filterViewerAndScreenSize( - item: IMapNavigationItem, - viewState: ViewState -) { - const currentViewer = viewState.terria.mainViewer.viewerMode; - const screenSize: ScreenSize = item.screenSize ?? "any"; - if (viewState.useSmallScreenInterface) { - return ( - (!isDefined(item.controller.viewerMode) || - item.controller.viewerMode === currentViewer) && - (screenSize === "any" || item.screenSize === "small") - ); - } else { - return ( - (!isDefined(item.controller.viewerMode) || - item.controller.viewerMode === currentViewer) && - (screenSize === "any" || item.screenSize === "medium") - ); - } -} diff --git a/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts b/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts new file mode 100644 index 00000000000..d555f60305a --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts @@ -0,0 +1,25 @@ +import isDefined from "../../../Core/isDefined"; +import ViewState from "../../../ReactViewModels/ViewState"; +import { ScreenSize } from "../../../ViewModels/CompositeBar/CompositeBarModel"; +import { IMapNavigationItem } from "../../../ViewModels/MapNavigation/MapNavigationModel"; + +export function filterViewerAndScreenSize( + item: IMapNavigationItem, + viewState: ViewState +) { + const currentViewer = viewState.terria.mainViewer.viewerMode; + const screenSize: ScreenSize = item.screenSize ?? "any"; + if (viewState.useSmallScreenInterface) { + return ( + (!isDefined(item.controller.viewerMode) || + item.controller.viewerMode === currentViewer) && + (screenSize === "any" || item.screenSize === "small") + ); + } else { + return ( + (!isDefined(item.controller.viewerMode) || + item.controller.viewerMode === currentViewer) && + (screenSize === "any" || item.screenSize === "medium") + ); + } +} diff --git a/lib/ReactViews/Map/MapNavigation/index.ts b/lib/ReactViews/Map/MapNavigation/index.ts new file mode 100644 index 00000000000..0511deeab3f --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/index.ts @@ -0,0 +1,2 @@ +export { CollapsedNavigation } from "./CollapsedNavigation"; +export { MapNavigation } from "./MapNavigation"; diff --git a/lib/ReactViews/Map/Navigation/registerMapNavigations.tsx b/lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx similarity index 92% rename from lib/ReactViews/Map/Navigation/registerMapNavigations.tsx rename to lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx index 2a3a731c1e2..3c48d555e87 100644 --- a/lib/ReactViews/Map/Navigation/registerMapNavigations.tsx +++ b/lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx @@ -18,14 +18,16 @@ import { AugmentedVirtualityController, AugmentedVirtualityHoverController, AugmentedVirtualityRealign, - AugmentedVirtualityRealignController -} from "./Items/AugmentedVirtualityTool"; -import CloseToolButton from "./Items/CloseToolButton"; -import Compass, { COMPASS_TOOL_ID } from "./Items/Compass"; -import MeasureTool from "./Items/MeasureTool"; -import MyLocation from "./Items/MyLocation"; -import { ToggleSplitterController } from "./Items/ToggleSplitterTool"; -import ZoomControl, { ZOOM_CONTROL_ID } from "./Items/ZoomControl"; + AugmentedVirtualityRealignController, + CloseToolButton, + Compass, + COMPASS_TOOL_ID, + MeasureTool, + MyLocation, + ToggleSplitterController, + ZoomControl, + ZOOM_CONTROL_ID +} from "./Items"; export const CLOSE_TOOL_ID = "close-tool"; @@ -135,7 +137,7 @@ export const registerMapNavigations = (viewState: ViewState) => { location: "TOP", screenSize: undefined, controller: closeToolButtonController, - render: , + render: , order: 7 }); closeToolButtonController.setVisible(false); diff --git a/lib/ReactViews/Map/HelpButton/HelpButton.tsx b/lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx similarity index 85% rename from lib/ReactViews/Map/HelpButton/HelpButton.tsx rename to lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx index f0df7e8cbf4..2bfb674249a 100644 --- a/lib/ReactViews/Map/HelpButton/HelpButton.tsx +++ b/lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx @@ -1,10 +1,10 @@ import { observer } from "mobx-react"; import React from "react"; import { useTranslation } from "react-i18next"; -import Icon from "../../../Styled/Icon"; -import Text from "../../../Styled/Text"; -import Prompt from "../../Generic/Prompt"; -import { useViewState } from "../../StandardUserInterface/ViewStateContext"; +import Icon from "../../../../Styled/Icon"; +import Text from "../../../../Styled/Text"; +import Prompt from "../../../Generic/Prompt"; +import { useViewState } from "../../../Context"; import Styles from "./help-button.scss"; diff --git a/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss new file mode 100644 index 00000000000..fa774176e12 --- /dev/null +++ b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss @@ -0,0 +1,4 @@ +.helpBtn { + composes: btn from "../../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../../Sass/common/_buttons.scss"; +} diff --git a/lib/ReactViews/Map/HelpButton/help-button.scss.d.ts b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/HelpButton/help-button.scss.d.ts rename to lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss.d.ts diff --git a/lib/ReactViews/Map/MenuBar.jsx b/lib/ReactViews/Map/MenuBar/MenuBar.jsx similarity index 90% rename from lib/ReactViews/Map/MenuBar.jsx rename to lib/ReactViews/Map/MenuBar/MenuBar.jsx index 14530ef9f57..51466898134 100644 --- a/lib/ReactViews/Map/MenuBar.jsx +++ b/lib/ReactViews/Map/MenuBar/MenuBar.jsx @@ -4,14 +4,14 @@ import { observer } from "mobx-react"; import PropTypes from "prop-types"; import React from "react"; import styled from "styled-components"; -import withControlledVisibility from "../../ReactViews/HOCs/withControlledVisibility"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; -import HelpButton from "./HelpButton/HelpButton"; -import LangPanel from "./Panels/LangPanel/LangPanel"; -import SettingPanel from "./Panels/SettingPanel"; -import SharePanel from "./Panels/SharePanel/SharePanel"; -import ToolsPanel from "./Panels/ToolsPanel/ToolsPanel"; +import withControlledVisibility from "../../HOCs/withControlledVisibility"; +import { useViewState } from "../../Context"; +import LangPanel from "../Panels/LangPanel/LangPanel"; +import SettingPanel from "../Panels/SettingPanel"; +import SharePanel from "../Panels/SharePanel/SharePanel"; +import ToolsPanel from "../Panels/ToolsPanel/ToolsPanel"; import StoryButton from "./StoryButton/StoryButton"; +import HelpButton from "./HelpButton/HelpButton"; import Styles from "./menu-bar.scss"; diff --git a/lib/ReactViews/Map/StoryButton/StoryButton.tsx b/lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx similarity index 88% rename from lib/ReactViews/Map/StoryButton/StoryButton.tsx rename to lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx index 14a24c72158..afc1afb5972 100644 --- a/lib/ReactViews/Map/StoryButton/StoryButton.tsx +++ b/lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx @@ -2,13 +2,13 @@ import React, { Ref } from "react"; import { Trans, useTranslation } from "react-i18next"; import { DefaultTheme } from "styled-components"; -import triggerResize from "../../../Core/triggerResize"; -import Terria from "../../../Models/Terria"; -import ViewState from "../../../ReactViewModels/ViewState"; -import Icon from "../../../Styled/Icon"; -import Text from "../../../Styled/Text"; -import Prompt from "../../Generic/Prompt"; -import { useRefForTerria } from "../../Hooks/useRefForTerria"; +import triggerResize from "../../../../Core/triggerResize"; +import Terria from "../../../../Models/Terria"; +import ViewState from "../../../../ReactViewModels/ViewState"; +import Icon from "../../../../Styled/Icon"; +import Text from "../../../../Styled/Text"; +import Prompt from "../../../Generic/Prompt"; +import { useRefForTerria } from "../../../Hooks/useRefForTerria"; import Styles from "./story-button.scss"; diff --git a/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss new file mode 100644 index 00000000000..b3aa3dad359 --- /dev/null +++ b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss @@ -0,0 +1,13 @@ +@import "~terriajs-variables"; + +.storyBtn { + composes: btn from "../../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../../Sass/common/_buttons.scss"; + + &:hover, + &:focus { + svg { + fill: #ffffff; + } + } +} diff --git a/lib/ReactViews/Map/StoryButton/story-button.scss.d.ts b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/StoryButton/story-button.scss.d.ts rename to lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss.d.ts diff --git a/lib/ReactViews/Map/menu-bar.scss b/lib/ReactViews/Map/MenuBar/menu-bar.scss similarity index 83% rename from lib/ReactViews/Map/menu-bar.scss rename to lib/ReactViews/Map/MenuBar/menu-bar.scss index 97656d4e0df..0508b8c6abc 100644 --- a/lib/ReactViews/Map/menu-bar.scss +++ b/lib/ReactViews/Map/MenuBar/menu-bar.scss @@ -22,9 +22,9 @@ margin-left: 165px; } .menu { - composes: list-reset from "../../Sass/common/_base.scss"; - composes: clearfix from "../../Sass/common/_base.scss"; - composes: sm-show from "../../Sass/common/_base.scss"; + composes: list-reset from "../../../Sass/common/_base.scss"; + composes: clearfix from "../../../Sass/common/_base.scss"; + composes: sm-show from "../../../Sass/common/_base.scss"; margin: 0 $padding-small $padding-small $padding-small; @@ -75,11 +75,11 @@ } .flex { - composes: flex from "../../Sass/common/_base.scss"; + composes: flex from "../../../Sass/common/_base.scss"; } .langBtn { - composes: btn from "../../Sass/common/_buttons.scss"; - composes: btn--map from "../../Sass/common/_buttons.scss"; + composes: btn from "../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../Sass/common/_buttons.scss"; text-transform: uppercase; } diff --git a/lib/ReactViews/Map/menu-bar.scss.d.ts b/lib/ReactViews/Map/MenuBar/menu-bar.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/menu-bar.scss.d.ts rename to lib/ReactViews/Map/MenuBar/menu-bar.scss.d.ts diff --git a/lib/ReactViews/Map/Navigation/FullScreenButton.jsx b/lib/ReactViews/Map/Navigation/FullScreenButton.jsx deleted file mode 100644 index 36b8f1ec15a..00000000000 --- a/lib/ReactViews/Map/Navigation/FullScreenButton.jsx +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -const React = require("react"); -const createReactClass = require("create-react-class"); -const PropTypes = require("prop-types"); -import Styles from "./full_screen_button.scss"; -import classNames from "classnames"; -import Icon from "../../../Styled/Icon"; - -// The button to make the map full screen and hide the workbench. -const FullScreenButton = createReactClass({ - displayName: "FullScreenButton", - - propTypes: { - terria: PropTypes.object, - viewState: PropTypes.object.isRequired, - animationDuration: PropTypes.number // Defaults to 1 millisecond. - }, - - getInitialState() { - return { - isActive: false - }; - }, - - toggleFullScreen() { - this.props.viewState.setIsMapFullScreen( - !this.props.viewState.isMapFullScreen - ); - }, - - renderButtonText() { - if (this.props.viewState.isMapFullScreen) { - return Show Workbench; - } else { - return ; - } - }, - - render() { - const btnClassName = classNames(Styles.btn, { - [Styles.isActive]: this.props.viewState.isMapFullScreen - }); - const btnTitle = this.props.viewState.isMapFullScreen - ? "Show workbench" - : "Hide workbench"; - return ( -
- -
- ); - } -}); -module.exports = FullScreenButton; diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx index 6823a29fc26..aa6e72ee181 100644 --- a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx +++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx @@ -14,7 +14,7 @@ import Icon, { StyledIcon } from "../../../../Styled/Icon"; import Spacing from "../../../../Styled/Spacing"; import Text from "../../../../Styled/Text"; import parseCustomMarkdownToReact from "../../../Custom/parseCustomMarkdownToReact"; -import { withViewState } from "../../../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../../../Context"; import HelpPanelItem from "./HelpPanelItem"; export const HELP_PANEL_ID = "help"; diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx index d93280354da..c2bca7af626 100644 --- a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx +++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx @@ -10,7 +10,7 @@ import { import { isJsonString } from "../../../../Core/Json"; import Icon, { StyledIcon } from "../../../../Styled/Icon"; import Text from "../../../../Styled/Text"; -import { applyTranslationIfExists } from "./../../../../Language/languageHelpers"; +import { applyTranslationIfExists } from "../../../../Language/languageHelpers"; import HelpVideoPanel from "./HelpVideoPanel"; @observer diff --git a/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx b/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx index f05b81a990d..2ad49bc15b8 100644 --- a/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx +++ b/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx @@ -6,7 +6,7 @@ import { RawButton } from "../../../../Styled/Button"; import Icon from "../../../../Styled/Icon"; import Ul, { Li } from "../../../../Styled/List"; import MenuPanel from "../../../StandardUserInterface/customizable/MenuPanel"; -import Styles from "../../menu-bar.scss"; +import Styles from "../../MenuBar/menu-bar.scss"; const stripLangLocale = (lang: string = ""): string => lang.split("-")[0]; diff --git a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx index 094fe520987..8f283732101 100644 --- a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx +++ b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx @@ -2,9 +2,9 @@ import DOMPurify from "dompurify"; import React, { useEffect, useRef, useState } from "react"; import ReactDOM from "react-dom"; import { StyleSheetManager, ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../StandardUserInterface/StandardTheme"; -import { useViewState } from "../../../../StandardUserInterface/ViewStateContext"; -import DistanceLegend from "../../../Legend/DistanceLegend"; +import { terriaTheme } from "../../../../StandardUserInterface"; +import { useViewState } from "../../../../Context"; +import { DistanceLegend } from "../../../BottomBar/DistanceLegend"; import { buildShareLink, buildShortShareLink, @@ -72,10 +72,19 @@ const styles = ` padding: 5px; } + .tjs-legend__distanceLegend > label { + color: black; + } + + .tjs-legend__distanceLegend:hover { + background: #fff; + } + .tjs-legend__bar { border-bottom: 3px solid black; border-right: 3px solid black; border-left: 3px solid black; + margin: 0 auto; } body { @@ -174,7 +183,6 @@ const PrintView = (props: Props) => { {screenshot ? ( 0 ? rawPercentage : 100); - - this.setState({ - percentage: sanitisedPercentage - }); - } - - setMode(loading) { - this.setState({ loading: loading }); - } - - componentWillUnmount() { - this.eventHelper.removeAll(); - } - - /** - * Progress bar is influced by two loading states: - * The base globe where the progress bar shows actual progress, - * Sources where load progress is indeterminate including 3DTilesets where the progress bar is animated. - */ - render() { - const determinateProgress = this.state.percentage + "%"; - const indeterminateStillLoading = this.state.loading; - const allComplete = this.state.percentage === 100 && !this.state.loading; - - // use the baseMapContrastColor to ensure progress bar is visible on light backgrounds. If contrast color is white, use it. If its black, use the primary color of the current theme. - const backgroundColor = - this.props.viewState.terria.baseMapContrastColor === "#ffffff" - ? "#ffffff" - : this.props.theme.colorPrimary; - - return ( -
- ); - } -} - -export default withViewState(withTheme(ProgressBar)); diff --git a/lib/ReactViews/Map/ProgressBar.tsx b/lib/ReactViews/Map/ProgressBar.tsx new file mode 100644 index 00000000000..9fcc5359d60 --- /dev/null +++ b/lib/ReactViews/Map/ProgressBar.tsx @@ -0,0 +1,90 @@ +import React, { VFC, useCallback, useEffect, useMemo, useState } from "react"; +import styled, { css, keyframes, useTheme } from "styled-components"; +import EventHelper from "terriajs-cesium/Source/Core/EventHelper"; +import { useViewState } from "../Context"; + +export const ProgressBar: VFC = () => { + const [loadPercentage, setLoadPercentage] = useState(0); + const [indeterminateLoading, setIndeterminateLoading] = useState(); + + const theme = useTheme(); + const { terria } = useViewState(); + + const setProgress = useCallback((remaining: number, max: number) => { + const rawPercentage = (1 - remaining / max) * 100; + const sanitisedPercentage = Math.floor(remaining > 0 ? rawPercentage : 100); + setLoadPercentage(sanitisedPercentage); + }, []); + + const setMode = (mode: boolean) => { + setIndeterminateLoading(mode); + }; + + useEffect(() => { + const eventHelper = new EventHelper(); + + eventHelper.add(terria.tileLoadProgressEvent, setProgress); + + eventHelper.add(terria.indeterminateTileLoadProgressEvent, setMode); + + return () => { + eventHelper.removeAll(); + }; + }, []); + + const backgroundColor = useMemo( + () => + terria.baseMapContrastColor === "#ffffff" + ? "#ffffff" + : theme.colorPrimary, + [terria.baseMapContrastColor] + ); + + const allComplete = loadPercentage === 100 && !indeterminateLoading; + + return ( + + ); +}; + +interface IStyledProgressBarProps { + loadPercentage: string; + complete: boolean; + indeterminate: boolean; + backgroundColor: string; +} + +const StyledProgressBar = styled.div` + height: 5px; + overflow: hidden; + transition: opacity 200ms linear, width 200ms linear, visibility 400ms linear; + background-color: ${(props) => props.backgroundColor}; + width: ${(props) => props.loadPercentage}; + + ${(props) => props.complete && `visibility: hidden;`} + + ${(props) => + props.indeterminate && + css` + width: 100%; + animation: ${indeterminateAnimation} 1.2s infinite linear; + transform-origin: 0% 50%; + `} +`; + +const indeterminateAnimation = keyframes` + 0% { + transform: translateX(0) scaleX(0); + } + 40% { + transform: translateX(0) scaleX(0.4); + } + 100% { + transform: translateX(100%) scaleX(0.5); + } +}`; diff --git a/lib/ReactViews/Map/Splitter.jsx b/lib/ReactViews/Map/Splitter.jsx deleted file mode 100644 index 9031e37bd44..00000000000 --- a/lib/ReactViews/Map/Splitter.jsx +++ /dev/null @@ -1,231 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { withTranslation } from "react-i18next"; -import { GLYPHS, StyledIcon } from "../../Styled/Icon"; -import Styles from "./splitter.scss"; -import { observer } from "mobx-react"; -import { runInAction } from "mobx"; - -// 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; - } - }); - - window.addEventListener("test", null, options); - window.removeEventListener("test", null, options); -} catch (err) {} - -const notPassive = passiveSupported ? { passive: false } : false; - -@observer -class Splitter extends React.Component { - static propTypes = { - terria: PropTypes.object.isRequired, - viewState: PropTypes.object.isRequired, - thumbSize: PropTypes.number, - padding: PropTypes.number, - t: PropTypes.func.isRequired - }; - - static defaultProps = { - thumbSize: 42, - padding: 0 - }; - - constructor(props) { - super(props); - this.forceRefresh = this.forceRefresh.bind(this); - this.drag = this.drag.bind(this); - this.startDrag = this.startDrag.bind(this); - this.stopDrag = this.stopDrag.bind(this); - } - - componentDidMount() { - const that = this; - window.addEventListener("resize", function () { - that.forceRefresh(); - }); - } - - componentWillUnmount() { - this.unsubscribe(); - } - - forceRefresh() { - const smallChange = - this.props.terria.splitPosition < 0.5 ? 0.0001 : -0.0001; // Make sure never <0 or >1. - runInAction(() => { - this.props.terria.splitPosition += smallChange; - }); - } - - startDrag(event) { - const viewer = this.props.terria.currentViewer; - viewer.pauseMapInteraction(); - - // While dragging is in progress, subscribe to document-level movement and up events. - document.addEventListener("mousemove", this.drag, notPassive); - document.addEventListener("touchmove", this.drag, notPassive); - document.addEventListener("mouseup", this.stopDrag, notPassive); - document.addEventListener("touchend", this.stopDrag, notPassive); - - event.preventDefault(); - event.stopPropagation(); - } - - drag(event) { - let clientX = event.clientX; - let clientY = event.clientY; - if (event.targetTouches && event.targetTouches.length > 0) { - clientX = event.targetTouches.item(0).clientX; - clientY = event.targetTouches.item(0).clientY; - } - - const viewer = this.props.terria.mainViewer.currentViewer; - const container = viewer.getContainer(); - const mapRect = container.getBoundingClientRect(); - - const that = this; - function computeSplitFraction(startBound, endBound, position) { - const difference = endBound - startBound; - const fraction = (position - startBound) / difference; - - const min = startBound + that.props.padding + that.props.thumbSize * 0.5; - const max = endBound - that.props.padding - that.props.thumbSize * 0.5; - const minFraction = (min - startBound) / difference; - const maxFraction = (max - startBound) / difference; - - return Math.min(maxFraction, Math.max(minFraction, fraction)); - } - let splitFractionX = computeSplitFraction( - mapRect.left, - mapRect.right, - clientX - ); - let splitFractionY = computeSplitFraction( - mapRect.top, - mapRect.bottom, - clientY - ); - - // 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. - const minX = computeSplitFraction( - mapRect.left, - mapRect.right, - mapRect.left + 100 - ); - const maxX = computeSplitFraction( - mapRect.left, - mapRect.right, - mapRect.right - 100 - ); - // 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(() => { - this.props.terria.splitPosition = splitFractionX; - this.props.terria.splitPositionVertical = splitFractionY; - }); - - event.preventDefault(); - event.stopPropagation(); - } - - stopDrag(event) { - this.unsubscribe(); - - const viewer = this.props.terria.currentViewer; - // Ensure splitter stays in sync with map - this.props.viewState.triggerResizeEvent(); - - viewer.resumeMapInteraction(); - - event.preventDefault(); - event.stopPropagation(); - } - - unsubscribe() { - document.removeEventListener("mousemove", this.drag, notPassive); - document.removeEventListener("touchmove", this.drag, notPassive); - document.removeEventListener("mouseup", this.stopDrag, notPassive); - document.removeEventListener("touchend", this.stopDrag, notPassive); - window.removeEventListener("resize", this.forceRefresh); - } - - getPosition() { - const canvasWidth = - this.props.terria.currentViewer.getContainer().clientWidth; - const canvasHeight = - this.props.terria.currentViewer.getContainer().clientHeight; - return { - x: this.props.terria.splitPosition * canvasWidth, - y: this.props.terria.splitPositionVertical * canvasHeight - }; - } - - render() { - if ( - !this.props.terria.showSplitter || - !this.props.terria.currentViewer.canShowSplitter || - !this.props.terria.currentViewer.getContainer() - ) { - return null; - } - - const thumbWidth = this.props.thumbSize; - const position = this.getPosition(); - - const dividerStyle = { - left: position.x + "px", - backgroundColor: this.props.terria.baseMapContrastColor - }; - - const thumbStyle = { - left: position.x + "px", - top: position.y + "px", - width: thumbWidth + "px", - height: thumbWidth + "px", - marginLeft: "-" + thumbWidth * 0.5 + "px", - marginTop: "-" + thumbWidth * 0.5 + "px", - lineHeight: thumbWidth - 2 + "px", - borderRadius: thumbWidth * 0.5 + "px", - fontSize: thumbWidth - 12 + "px" - }; - - const { t } = this.props; - - return ( -
-
-
-
- -
- ); - } -} - -module.exports = withTranslation()(Splitter); diff --git a/lib/ReactViews/Map/StoryButton/story-button.scss b/lib/ReactViews/Map/StoryButton/story-button.scss deleted file mode 100644 index 51c17ff0a88..00000000000 --- a/lib/ReactViews/Map/StoryButton/story-button.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import "~terriajs-variables"; - -.storyBtn { - composes: btn from "../../../Sass/common/_buttons.scss"; - composes: btn--map from "../../../Sass/common/_buttons.scss"; - - &:hover, - &:focus { - svg { - fill: #ffffff; - } - } -} diff --git a/lib/ReactViews/Map/TerriaViewerWrapper.jsx b/lib/ReactViews/Map/TerriaViewerWrapper.jsx deleted file mode 100644 index e90d9beb9dc..00000000000 --- a/lib/ReactViews/Map/TerriaViewerWrapper.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { observer } from "mobx-react"; - -import Styles from "./terria-viewer-wrapper.scss"; - -import Splitter from "./Splitter"; -// eslint-disable-next-line no-unused-vars -import TerriaViewer from "../../ViewModels/TerriaViewer"; - -/** - * @typedef {object} Props - * @prop {Terria} terria - * @prop {ViewState} viewState - * - * @extends {React.Component} - */ -@observer -class TerriaViewerWrapper extends React.Component { - static propTypes = { - terria: PropTypes.object.isRequired, - viewState: PropTypes.object.isRequired - }; - - /** - * @argument {HTMLDivElement} container - */ - containerRef = (container) => { - this.props.terria.mainViewer.attached && - this.props.terria.mainViewer.detach(); - if (container !== null) { - this.props.terria.mainViewer.attach(container); - } - }; - - componentWillUnmount() { - this.props.terria.mainViewer.attached && - this.props.terria.mainViewer.detach(); - } - - render() { - return ( - - ); - } -} -module.exports = TerriaViewerWrapper; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx new file mode 100644 index 00000000000..664abf6a569 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx @@ -0,0 +1,102 @@ +import { runInAction } from "mobx"; +import { observer } from "mobx-react"; +import React, { FC, useCallback, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useTheme } from "styled-components"; +import Terria from "../../../../Models/Terria"; +import { GLYPHS, StyledIcon } from "../../../../Styled/Icon"; +import { useViewState } from "../../../Context"; +import { useDragHook } from "./dragHook"; + +interface ISplitterProps { + thumbSize?: number; + padding?: number; +} + +export const Splitter: FC = observer( + ({ thumbSize = 42, padding = 0 }) => { + const viewState = useViewState(); + const theme = useTheme(); + const { t } = useTranslation(); + + const { startDrag, dragUnsubscribe } = useDragHook( + viewState, + padding, + thumbSize + ); + + const onResize = useCallback(() => { + const smallChange = + viewState.terria.splitPosition < 0.5 ? 0.0001 : -0.0001; // Make sure never <0 or >1. + runInAction(() => { + viewState.terria.splitPosition += smallChange; + }); + }, [viewState]); + + useEffect(() => { + window.addEventListener("resize", onResize); + return () => { + dragUnsubscribe(); + window.removeEventListener("resize", onResize); + }; + }, [onResize, dragUnsubscribe]); + + if ( + !viewState.terria.showSplitter || + !viewState.terria.currentViewer.canShowSplitter || + !viewState.terria.currentViewer.getContainer() + ) { + return null; + } + + const position = getPosition(viewState.terria); + + return ( +
+
+
+
+ +
+ ); + } +); + +const getPosition = (terria: Terria) => { + const canvasWidth = terria.currentViewer.getContainer()?.clientWidth || 0; + const canvasHeight = terria.currentViewer.getContainer()?.clientHeight || 0; + return { + x: terria.splitPosition * canvasWidth, + y: terria.splitPositionVertical * canvasHeight + }; +}; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts new file mode 100644 index 00000000000..2014e467f34 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts @@ -0,0 +1,166 @@ +import { runInAction } from "mobx"; +import { + MouseEvent as ReactMouseEvent, + TouchEvent as ReactTouchEvent, + useCallback +} from "react"; +import ViewState from "../../../../ReactViewModels/ViewState"; + +// 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: ViewState, + padding: number, + thumbSize: number +) => { + const drag = useCallback( + (e: MouseEvent | TouchEvent) => { + let clientX: number | undefined = undefined; + let clientY: number | undefined = 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. + const minX = computeSplitFraction( + mapRect.left, + mapRect.right, + mapRect.left + 100, + 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(); + }, + [viewState] + ); + + const stopDrag = useCallback( + (e: Event) => { + dragUnsubscribe(); + + const viewer = viewState.terria.currentViewer; + // Ensure splitter stays in sync with map + viewState.triggerResizeEvent(); + + viewer.resumeMapInteraction(); + + e.preventDefault(); + e.stopPropagation(); + }, + [viewState] + ); + + const startDrag = useCallback( + (e: ReactMouseEvent | ReactTouchEvent | undefined) => { + 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 as never); + document.removeEventListener("touchmove", drag, notPassive as never); + document.removeEventListener("mouseup", stopDrag, notPassive as never); + document.removeEventListener("touchend", stopDrag, notPassive as never); + }, [drag, stopDrag]); + + return { startDrag, dragUnsubscribe }; +}; + +function computeSplitFraction( + startBound: number, + endBound: number, + position: number, + padding: number, + thumbSize: number +) { + 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)); +} diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx b/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx new file mode 100644 index 00000000000..b66aa1f51ed --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx @@ -0,0 +1,84 @@ +import React, { FC, useEffect, useRef } from "react"; + +import { Splitter } from "./Splitter/Splitter"; +import { useViewState } from "../../Context"; +import styled from "styled-components"; + +export const TerriaViewerWrapper: FC = () => { + const viewState = useViewState(); + const containerRef = useRef(null); + + useEffect(() => { + if (viewState.terria.mainViewer.attached) { + viewState.terria.mainViewer.detach(); + } + if (containerRef.current) { + viewState.terria.mainViewer.attach(containerRef.current); + } + + return () => { + viewState.terria.mainViewer.detach(); + }; + }, [viewState]); + + return ( + + + Loading the map, please wait... + + +
+ + ); +}; + +const TerrriaViewerContainer = styled.aside` + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +`; + +const StyledMapPlaceholder = styled.div` + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + color: black; + text-align: center; + width: 100%; + height: 25%; + margin: auto; + @media (min-width: ${(p) => p.theme.sm}px) { + color: white; + } +`; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/index.ts b/lib/ReactViews/Map/TerriaViewerWrapper/index.ts new file mode 100644 index 00000000000..fb3377a1c87 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/index.ts @@ -0,0 +1 @@ +export { TerriaViewerWrapper } from "./TerriaViewerWrapper"; diff --git a/lib/ReactViews/StandardUserInterface/Toast.tsx b/lib/ReactViews/Map/Toast.tsx similarity index 100% rename from lib/ReactViews/StandardUserInterface/Toast.tsx rename to lib/ReactViews/Map/Toast.tsx diff --git a/lib/ReactViews/Map/experimental-features.scss b/lib/ReactViews/Map/experimental-features.scss deleted file mode 100644 index c9a98d01566..00000000000 --- a/lib/ReactViews/Map/experimental-features.scss +++ /dev/null @@ -1,22 +0,0 @@ -@import "~terriajs-variables"; - -.experimental-features { - position: absolute; - left: 25px; - bottom: 25px; - z-index: 1; - - @media (min-width: $sm) { - top: auto; - bottom: 100px; - } -} - -.control { - margin: 15px 0; - text-align: center; - - &:last-child { - margin-bottom: 0; - } -} diff --git a/lib/ReactViews/Map/experimental-features.scss.d.ts b/lib/ReactViews/Map/experimental-features.scss.d.ts deleted file mode 100644 index d84db085ee8..00000000000 --- a/lib/ReactViews/Map/experimental-features.scss.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'control': string; - 'experimental-features': string; - 'experimentalFeatures': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/progress-bar.scss b/lib/ReactViews/Map/progress-bar.scss deleted file mode 100644 index 7e05acb098d..00000000000 --- a/lib/ReactViews/Map/progress-bar.scss +++ /dev/null @@ -1,31 +0,0 @@ -.progress-bar { - z-index: 1; - position: absolute; - top: 0; - left: 0; - height: 5px; - overflow: hidden; - transition: opacity 200ms linear, width 200ms linear, visibility 400ms linear; -} - -.complete { - visibility: hidden; -} - -.indeterminate-bar-animated { - width: 100%; - animation: indeterminateAnimation 1.2s infinite linear; - transform-origin: 0% 50%; -} - -@keyframes indeterminateAnimation { - 0% { - transform: translateX(0) scaleX(0); - } - 40% { - transform: translateX(0) scaleX(0.4); - } - 100% { - transform: translateX(100%) scaleX(0.5); - } -} diff --git a/lib/ReactViews/Map/progress-bar.scss.d.ts b/lib/ReactViews/Map/progress-bar.scss.d.ts deleted file mode 100644 index ae6c7a6c853..00000000000 --- a/lib/ReactViews/Map/progress-bar.scss.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'complete': string; - 'indeterminate-bar-animated': string; - 'indeterminateAnimation': string; - 'indeterminateBarAnimated': string; - 'progress-bar': string; - 'progressBar': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/splitter.scss b/lib/ReactViews/Map/splitter.scss deleted file mode 100644 index 9849d3c22d8..00000000000 --- a/lib/ReactViews/Map/splitter.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "~terriajs-variables"; - -.divider-wrapper { - position: absolute; - width: 100%; - height: 100%; -} - -.divider { - position: absolute; - top: 0; - bottom: 0; - left: 50%; - width: 1px; - background-color: #fff; - pointer-events: none; - z-index: 999; -} - -.thumb { - position: absolute; - width: 40px; - height: 40px; - border-radius: 20px; - border: 1px solid lightgrey; - text-align: center; - line-height: 38px; - left: 50%; - top: 50%; - font-size: 28px; - font-family: monospace; - background-color: white; - color: grey; - margin-top: -20px; - margin-left: -20px; - z-index: 999; - padding: 8px; - cursor: ew-resize; - svg { - fill: #000; - } -} diff --git a/lib/ReactViews/Map/splitter.scss.d.ts b/lib/ReactViews/Map/splitter.scss.d.ts deleted file mode 100644 index e6984139b8c..00000000000 --- a/lib/ReactViews/Map/splitter.scss.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'divider': string; - 'divider-wrapper': string; - 'dividerWrapper': string; - 'thumb': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/terria-viewer-wrapper.scss b/lib/ReactViews/Map/terria-viewer-wrapper.scss deleted file mode 100644 index 21961915fee..00000000000 --- a/lib/ReactViews/Map/terria-viewer-wrapper.scss +++ /dev/null @@ -1,57 +0,0 @@ -@import "~terriajs-variables"; -@import "../../Sass/common/mixins"; - -.container { - top: 0; - right: 0; - bottom: 0; - left: 0; - position: absolute; -} - -.cesium-container { - top: 0; - right: 0; - bottom: 0; - left: 0; - position: absolute; - cursor: auto; - - :global { - .selection-indicator { - pointer-events: none; - position: absolute; - width: 50px; - height: 50px; - } - - #terriaLogoWrapper { - display: inline-block; - } - - .cesium-widget, - .cesium-widget canvas { - position: absolute; - width: 100%; - height: 100%; - touch-action: none; - } - } -} - -.mapPlaceholder { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - color: black; - text-align: center; - width: 100%; - height: 25%; - margin: auto; - - @media (min-width: $sm) { - color: white; - } -} diff --git a/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts b/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts deleted file mode 100644 index 8f5c50b26cb..00000000000 --- a/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'cesium-container': string; - 'cesiumContainer': string; - 'container': string; - 'mapPlaceholder': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Mobile/MobileHeader.jsx b/lib/ReactViews/Mobile/MobileHeader.jsx index f0858d21f14..63800fa92a2 100644 --- a/lib/ReactViews/Mobile/MobileHeader.jsx +++ b/lib/ReactViews/Mobile/MobileHeader.jsx @@ -11,7 +11,7 @@ import { RawButton } from "../../Styled/Button"; import Icon, { StyledIcon } from "../../Styled/Icon"; import SearchBox from "../Search/SearchBox"; import Branding from "../SidePanel/Branding"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./mobile-header.scss"; import MobileMenu from "./MobileMenu"; import MobileModalWindow from "./MobileModalWindow"; @@ -260,7 +260,6 @@ class MobileHeader extends React.Component { menuItems={this.props.menuItems} menuLeftItems={this.props.menuLeftItems} viewState={this.props.viewState} - allBaseMaps={this.props.allBaseMaps} terria={this.props.viewState.terria} showFeedback={ !!this.props.viewState.terria.configParameters.feedbackUrl @@ -300,7 +299,6 @@ const HamburgerButton = styled(RawButton)` MobileHeader.propTypes = { viewState: PropTypes.object.isRequired, - allBaseMaps: PropTypes.array, version: PropTypes.string, menuLeftItems: PropTypes.array, menuItems: PropTypes.array, diff --git a/lib/ReactViews/Notification/MapInteractionWindow.tsx b/lib/ReactViews/Notification/MapInteractionWindow.tsx index 75aa172fba1..4c476613ab8 100644 --- a/lib/ReactViews/Notification/MapInteractionWindow.tsx +++ b/lib/ReactViews/Notification/MapInteractionWindow.tsx @@ -10,7 +10,7 @@ import isDefined from "../../Core/isDefined"; import MapInteractionMode, { UIMode } from "../../Models/MapInteractionMode"; import ViewState from "../../ReactViewModels/ViewState"; import parseCustomHtmlToReact from "../Custom/parseCustomHtmlToReact"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./map-interaction-window.scss"; const MapInteractionWindowWrapper = styled.div<{ isDiffTool: boolean }>` diff --git a/lib/ReactViews/Notification/Notification.tsx b/lib/ReactViews/Notification/Notification.tsx index bf33f2c27b3..4b7e597d1bc 100644 --- a/lib/ReactViews/Notification/Notification.tsx +++ b/lib/ReactViews/Notification/Notification.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; import React from "react"; import triggerResize from "../../Core/triggerResize"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; // Avoid type error caused by importing untyped jsx const NotificationWindow = require("./NotificationWindow").default; diff --git a/lib/ReactViews/RelatedMaps/RelatedMaps.tsx b/lib/ReactViews/RelatedMaps/RelatedMaps.tsx index 8464d3490e9..2194252874a 100644 --- a/lib/ReactViews/RelatedMaps/RelatedMaps.tsx +++ b/lib/ReactViews/RelatedMaps/RelatedMaps.tsx @@ -6,10 +6,7 @@ import { RelatedMap } from "../../Models/RelatedMaps"; import Box from "../../Styled/Box"; import { ExternalLinkIcon } from "../Custom/ExternalLink"; import parseCustomMarkdownToReact from "../Custom/parseCustomMarkdownToReact"; -import { - withViewState, - WithViewState -} from "../StandardUserInterface/ViewStateContext"; +import { withViewState, WithViewState } from "../Context"; import Styles from "./related-maps.scss"; const MenuPanel = diff --git a/lib/ReactViews/SidePanel/Branding.tsx b/lib/ReactViews/SidePanel/Branding.tsx index 8e2b6fdda03..705f90549e3 100644 --- a/lib/ReactViews/SidePanel/Branding.tsx +++ b/lib/ReactViews/SidePanel/Branding.tsx @@ -4,7 +4,7 @@ import React from "react"; import isDefined from "../../Core/isDefined"; import ViewState from "../../ReactViewModels/ViewState"; import parseCustomHtmlToReact from "../Custom/parseCustomHtmlToReact"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; const DEFAULT_BRANDING = ''; diff --git a/lib/ReactViews/SidePanel/FullScreenButton.jsx b/lib/ReactViews/SidePanel/FullScreenButton.jsx index 7bff73db311..5f43f8e8f10 100644 --- a/lib/ReactViews/SidePanel/FullScreenButton.jsx +++ b/lib/ReactViews/SidePanel/FullScreenButton.jsx @@ -7,7 +7,7 @@ import { withTranslation } from "react-i18next"; import { Category, ViewAction } from "../../Core/AnalyticEvents/analyticEvents"; import Icon from "../../Styled/Icon"; import withControlledVisibility from "../HOCs/withControlledVisibility"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./full_screen_button.scss"; // The button to make the map full screen and hide the workbench. diff --git a/lib/ReactViews/SidePanel/SidePanel.tsx b/lib/ReactViews/SidePanel/SidePanel.tsx index ff3aefd9e14..58c06eaa18e 100644 --- a/lib/ReactViews/SidePanel/SidePanel.tsx +++ b/lib/ReactViews/SidePanel/SidePanel.tsx @@ -11,17 +11,21 @@ import Text from "../../Styled/Text"; import { ExplorerWindowElementName } from "../ExplorerWindow/ExplorerWindow"; import { useRefForTerria } from "../Hooks/useRefForTerria"; import SearchBoxAndResults from "../Search/SearchBoxAndResults"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Workbench from "../Workbench/Workbench"; const BoxHelpfulHints = styled(Box)``; const ResponsiveSpacing = styled(Box)` + height: 110px; height: 110px; // Hardcoded px value, TODO: make it not hardcoded @media (max-height: 700px) { height: 3vh; } + @media (max-height: 700px) { + height: 3vh; + } `; const HelpfulHintsIcon = () => { diff --git a/lib/ReactViews/Map/ExperimentalFeatures.tsx b/lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx similarity index 91% rename from lib/ReactViews/Map/ExperimentalFeatures.tsx rename to lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx index 4c897f61895..e16194b3861 100644 --- a/lib/ReactViews/Map/ExperimentalFeatures.tsx +++ b/lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx @@ -1,7 +1,7 @@ import React from "react"; import styled from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; interface IProps { viewState: ViewState; @@ -13,7 +13,6 @@ const ControlsWrapper = styled.div` left: 25px; bottom: 25px; z-index: 1; - @media (min-width: ${(props) => props.theme.sm}px) { top: auto; bottom: 100px; @@ -22,7 +21,6 @@ const ControlsWrapper = styled.div` const Control = styled.div` margin: 15px 0; text-align: center; - &:last-child { margin-bottom: 0; } diff --git a/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts b/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts index 8ed3aa75bb5..556bf96b116 100644 --- a/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts +++ b/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts @@ -67,4 +67,19 @@ body { button { cursor: pointer; } + +.selection-indicator { + pointer-events: none; + position: absolute; + width: 50px; + height: 50px; +} + +.cesium-widget, +.cesium-widget canvas { + position: absolute; + width: 100%; + height: 100%; + touch-action: none; +} `; diff --git a/lib/ReactViews/StandardUserInterface/MapColumn.jsx b/lib/ReactViews/StandardUserInterface/MapColumn.jsx deleted file mode 100644 index 1a7411ba12e..00000000000 --- a/lib/ReactViews/StandardUserInterface/MapColumn.jsx +++ /dev/null @@ -1,215 +0,0 @@ -import classNames from "classnames"; -import { observer } from "mobx-react"; -import PropTypes from "prop-types"; -import React from "react"; -import { withTranslation } from "react-i18next"; -import FeatureDetection from "terriajs-cesium/Source/Core/FeatureDetection"; -import ActionBarPortal from "../ActionBar/ActionBarPortal"; -import BottomDock from "../BottomDock/BottomDock"; -import { MapCredits } from "../Credits"; -import Loader from "../Loader"; -import BottomLeftBar from "../Map/BottomLeftBar/BottomLeftBar"; -import DistanceLegend from "../Map/Legend/DistanceLegend"; -import LocationBar from "../Map/Legend/LocationBar"; -import MenuBar from "../Map/MenuBar"; -import MapNavigation from "../Map/Navigation/MapNavigation"; -import TerriaViewerWrapper from "../Map/TerriaViewerWrapper"; -import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; -import Styles from "./map-column.scss"; -import Toast from "./Toast"; -import { withViewState } from "./ViewStateContext"; - -const chromeVersion = FeatureDetection.chromeVersion(); - -/** - * Right-hand column that contains the map, controls that sit over the map and sometimes the bottom dock containing - * the timeline and charts. - */ -@observer -class MapColumn extends React.Component { - static propTypes = { - viewState: PropTypes.object.isRequired, - customFeedbacks: PropTypes.array.isRequired, - allBaseMaps: PropTypes.array.isRequired, - animationDuration: PropTypes.number.isRequired, - customElements: PropTypes.object.isRequired, - t: PropTypes.func.isRequired - }; - - constructor(props) { - super(props); - this.state = {}; - } - - render() { - const { customElements } = this.props; - const { t } = this.props; - // TODO: remove? see: https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 - const isAboveChrome75 = - chromeVersion && chromeVersion[0] && Number(chromeVersion[0]) > 75; - const mapCellClass = classNames(Styles.mapCell, { - [Styles.mapCellChrome]: isAboveChrome75 - }); - return ( -
-
-
- -
- - -
-
-
- -
- - - - - - - - - -
- - -
-
- {/* TODO: re-implement/support custom feedbacks */} - {/* -
- -
-
*/} - - - -
{feedbackItem}
-
-
-
- - - -
- -
-
- -
-
-
-
- ); - } -} - -export default withTranslation()(withViewState(MapColumn)); diff --git a/lib/ReactViews/StandardUserInterface/Portal.tsx b/lib/ReactViews/StandardUserInterface/Portal.tsx index 5ee53a4e75e..e492c2274f8 100644 --- a/lib/ReactViews/StandardUserInterface/Portal.tsx +++ b/lib/ReactViews/StandardUserInterface/Portal.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import React, { useEffect } from "react"; import ReactDOM from "react-dom"; import ViewState from "../../ReactViewModels/ViewState"; -import { useViewState } from "./ViewStateContext"; +import { useViewState } from "../Context"; type PortalProps = { /** diff --git a/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx b/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx index 582810e0b12..e78d7c1eeb1 100644 --- a/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx +++ b/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx @@ -1,7 +1,7 @@ import { action } from "mobx"; import styled from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; -import { withViewState } from "./ViewStateContext"; +import { withViewState } from "../Context"; type PropsType = { viewState: ViewState; diff --git a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx index 17d3e476174..11571f4e972 100644 --- a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx +++ b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx @@ -17,12 +17,11 @@ import FeedbackForm from "../Feedback/FeedbackForm"; import { Medium, Small } from "../Generic/Responsive"; import SatelliteHelpPrompt from "../HelpScreens/SatelliteHelpPrompt"; import withFallback from "../HOCs/withFallback"; -import ExperimentalFeatures from "../Map/ExperimentalFeatures"; -import CollapsedNavigation from "../Map/Navigation/Items/OverflowNavigationItem"; +import ExperimentalFeatures from "./ExperimentalFeatures"; +import { CollapsedNavigation } from "../Map/MapNavigation"; import HelpPanel from "../Map/Panels/HelpPanel/HelpPanel"; import PrintView from "../Map/Panels/SharePanel/Print/PrintView"; -import ProgressBar from "../Map/ProgressBar"; -import TrainerBar from "../Map/TrainerBar/TrainerBar"; +import TrainerBar from "./TrainerBar/TrainerBar"; import MobileHeader from "../Mobile/MobileHeader"; import MapInteractionWindow from "../Notification/MapInteractionWindow"; import Notification from "../Notification/Notification"; @@ -35,9 +34,9 @@ import Tool from "../Tools/Tool"; import TourPortal from "../Tour/TourPortal"; import WelcomeMessage from "../WelcomeMessage/WelcomeMessage"; import SelectableDimensionWorkflow from "../Workflow/SelectableDimensionWorkflow"; -import ContextProviders from "./ContextProviders"; +import { ContextProviders } from "../Context"; import { GlobalTerriaStyles } from "./GlobalTerriaStyles"; -import MapColumn from "./MapColumn"; +import MapColumn from "../Map/MapColumn"; import processCustomElements from "./processCustomElements"; import SidePanelContainer from "./SidePanelContainer"; import Styles from "./standard-user-interface.scss"; @@ -49,15 +48,14 @@ export const animationDuration = 250; interface StandardUserInterfaceProps { terria: ViewState["terria"]; viewState: ViewState; - allBaseMaps?: any[]; themeOverrides?: Partial; minimumLargeScreenWidth?: number; version: string; children?: ReactNode; } -const StandardUserInterface: React.FC = observer( - (props) => { +const StandardUserInterfaceBase: React.FC = + observer((props) => { const { t } = useTranslation(); const acceptDragDropFile = action(() => { @@ -135,7 +133,6 @@ const StandardUserInterface: React.FC = observer( ); const terria = props.terria; - const allBaseMaps = props.allBaseMaps; const showStoryBuilder = props.viewState.storyBuilderShown && @@ -178,7 +175,6 @@ const StandardUserInterface: React.FC = observer( menuItems={customElements.menu} menuLeftItems={customElements.menuLeft} version={props.version} - allBaseMaps={allBaseMaps} /> @@ -228,11 +224,9 @@ const StandardUserInterface: React.FC = observer(
-
@@ -308,7 +302,7 @@ const StandardUserInterface: React.FC = observer( )} ); - } -); + }); -export default withFallback(StandardUserInterface); +export const StandardUserInterface = withFallback(StandardUserInterfaceBase); +export default withFallback(StandardUserInterfaceBase); diff --git a/lib/ReactViews/Map/TrainerBar/TrainerBar.tsx b/lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx similarity index 99% rename from lib/ReactViews/Map/TrainerBar/TrainerBar.tsx rename to lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx index f2ed5ad2ca3..3794c229355 100644 --- a/lib/ReactViews/Map/TrainerBar/TrainerBar.tsx +++ b/lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx @@ -17,10 +17,7 @@ import Select from "../../../Styled/Select"; import Spacing from "../../../Styled/Spacing"; import Text, { TextSpan } from "../../../Styled/Text"; import measureElement, { MeasureElementProps } from "../../HOCs/measureElement"; -import { - WithViewState, - withViewState -} from "../../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../../Context"; import { applyTranslationIfExists } from "./../../../Language/languageHelpers"; const StyledHtml: any = diff --git a/lib/ReactViews/Map/MenuButton.jsx b/lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx similarity index 95% rename from lib/ReactViews/Map/MenuButton.jsx rename to lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx index 52395c1ec2b..626bac2eacf 100644 --- a/lib/ReactViews/Map/MenuButton.jsx +++ b/lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx @@ -1,6 +1,6 @@ import React from "react"; import classNames from "classnames"; -import Icon from "../../Styled/Icon"; +import Icon from "../../../Styled/Icon"; import PropTypes from "prop-types"; import Styles from "./menu-button.scss"; diff --git a/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx b/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx index 9a8f1aaf321..897122345f0 100644 --- a/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx +++ b/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx @@ -1,4 +1,4 @@ -import MenuButton from "../../Map/MenuButton"; +import MenuButton from "./MenuButton"; import responsiveSwitch from "./ResponsiveSwitch"; import withControlledVisibility from "../../HOCs/withControlledVisibility"; import MobileMenuItem from "../../Mobile/MobileMenuItem"; diff --git a/lib/ReactViews/Map/menu-button.scss b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss similarity index 74% rename from lib/ReactViews/Map/menu-button.scss rename to lib/ReactViews/StandardUserInterface/customizable/menu-button.scss index eac534aec5d..b35fa5b3397 100644 --- a/lib/ReactViews/Map/menu-button.scss +++ b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss @@ -1,8 +1,8 @@ @import "~terriajs-variables"; .btn--about-link { - composes: btn from "../../Sass/common/_buttons.scss"; - composes: btn--map from "../../Sass/common/_buttons.scss"; + composes: btn from "../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../Sass/common/_buttons.scss"; border-radius: $radius-small; border: 0; svg { diff --git a/lib/ReactViews/Map/menu-button.scss.d.ts b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/menu-button.scss.d.ts rename to lib/ReactViews/StandardUserInterface/customizable/menu-button.scss.d.ts diff --git a/lib/ReactViews/StandardUserInterface/index.ts b/lib/ReactViews/StandardUserInterface/index.ts new file mode 100644 index 00000000000..f0f63b85c00 --- /dev/null +++ b/lib/ReactViews/StandardUserInterface/index.ts @@ -0,0 +1,5 @@ +export { + StandardUserInterface, + StandardUserInterface as default +} from "./StandardUserInterface"; +export { terriaTheme } from "./StandardTheme"; diff --git a/lib/ReactViews/StandardUserInterface/map-column.scss b/lib/ReactViews/StandardUserInterface/map-column.scss deleted file mode 100644 index 93bf7fa4475..00000000000 --- a/lib/ReactViews/StandardUserInterface/map-column.scss +++ /dev/null @@ -1,99 +0,0 @@ -@import "~terriajs-variables"; -@import "../../Sass/common/mixins"; - -.map__inner { - display: table; - width: 100%; - height: 100%; - - * { - box-sizing: border-box; - } -} -.map__innerChrome { - // Chrome only :( hack until - // https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 gets resolved - display: flex; - flex-flow: column; -} - -.map__row { - display: table-row; - - &:first-child { - height: 100%; - position: relative; - } -} - -.map__cell { - display: table-cell; - position: relative; - width: 100%; -} -.map__cellChrome { - // Chrome only :( hack until - // https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 gets resolved - display: block; - height: 100%; -} - -@include empty-module("map-cell-map"); - -.map-wrapper { - position: absolute; - top: 0; - width: 100%; - z-index: 0; -} - -@include empty-module("feedback"); - -.location-distance { - composes: clearfix from "../../Sass/common/_base.scss"; - display: none; - @media (min-width: $sm) { - display: block; - } - position: absolute; - bottom: 2px; - right: 3px; - z-index: 1; -} - -.feedback-button-wrapper { - @media (min-width: $sm) { - bottom: 100px; - right: $padding * 2; - margin: 0; - } - - @media (max-width: $mobile) { - position: fixed; - } - position: absolute; - z-index: 0; - bottom: 25px; - right: 16px; - margin: 4px 0; -} - -.with-time-series-controls { - bottom: 58px; - - @media (max-width: $mobile) { - bottom: $mobile-bottom-timeline; - } -} - -.print-disclaimer { - display: none; -} - -@media print { - .print-disclaimer { - display: block; - width: 100%; - clear: both; - } -} diff --git a/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts b/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts deleted file mode 100644 index 8f9308b3b49..00000000000 --- a/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'feedback': string; - 'feedback-button-wrapper': string; - 'feedbackButtonWrapper': string; - 'location-distance': string; - 'locationDistance': string; - 'map-cell-map': string; - 'map-wrapper': string; - 'mapCell': string; - 'mapCellChrome': string; - 'mapCellMap': string; - 'mapInner': string; - 'mapInnerChrome': string; - 'mapRow': string; - 'mapWrapper': string; - 'map__cell': string; - 'map__cellChrome': string; - 'map__inner': string; - 'map__innerChrome': string; - 'map__row': string; - 'print-disclaimer': string; - 'printDisclaimer': string; - 'with-time-series-controls': string; - 'withTimeSeriesControls': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Story/StoryBuilder.tsx b/lib/ReactViews/Story/StoryBuilder.tsx index 4797adccf6e..4525fcb2eee 100644 --- a/lib/ReactViews/Story/StoryBuilder.tsx +++ b/lib/ReactViews/Story/StoryBuilder.tsx @@ -27,10 +27,7 @@ import measureElement, { MeasureElementProps } from "../HOCs/measureElement"; import VideoGuide from "../Map/Panels/HelpPanel/VideoGuide"; import { getShareData } from "../Map/Panels/SharePanel/BuildShareLink"; import SharePanel from "../Map/Panels/SharePanel/SharePanel"; -import { - WithViewState, - withViewState -} from "../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../Context"; import Story from "./Story"; import Styles from "./story-builder.scss"; import StoryEditor from "./StoryEditor.jsx"; diff --git a/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx b/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx index 68c6c48b3b6..ee891ed530d 100644 --- a/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx +++ b/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx @@ -15,11 +15,8 @@ import TerriaError from "../../../Core/TerriaError"; import Terria from "../../../Models/Terria"; import Box from "../../../Styled/Box"; import Hr from "../../../Styled/Hr"; -import { onStoryButtonClick } from "../../Map/StoryButton/StoryButton"; -import { - WithViewState, - withViewState -} from "../../StandardUserInterface/ViewStateContext"; +import { onStoryButtonClick } from "../../Map/MenuBar/StoryButton/StoryButton"; +import { WithViewState, withViewState } from "../../Context"; import { Story } from "../Story"; import Styles from "../story-panel.scss"; import StoryBody from "./StoryBody"; diff --git a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx index 60ad3919660..04ad26a0218 100644 --- a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx +++ b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx @@ -51,7 +51,7 @@ import { GLYPHS, StyledIcon } from "../../../Styled/Icon"; import Loader from "../../Loader"; import DatePicker from "./DatePicker"; import LocationPicker from "./LocationPicker"; -import { CLOSE_TOOL_ID } from "../../Map/Navigation/registerMapNavigations"; +import { CLOSE_TOOL_ID } from "../../Map/MapNavigation/registerMapNavigations"; const dateFormat = require("dateformat"); @@ -843,7 +843,6 @@ const CloseDifferenceButton = styled(Button)` left: 50%; transform: translateX(-50%); top: 18px; - padding: 0 20px; `; diff --git a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx index f48dd76fb61..5d020221363 100644 --- a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx +++ b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx @@ -8,7 +8,7 @@ import PositionRightOfWorkbench from "../../Workbench/PositionRightOfWorkbench"; import DropPedestrianToGround from "./DropPedestrianToGround"; import MiniMap, { getViewFromScene, MiniMapView } from "./MiniMap"; import MovementControls from "./MovementControls"; -import MeasureTool from "../../Map/Navigation/Items/MeasureTool"; +import { MeasureTool } from "../../Map/MapNavigation/Items"; // The desired camera height measured from the surface in metres export const PEDESTRIAN_HEIGHT = 1.7; diff --git a/lib/ReactViews/Tools/Tool.tsx b/lib/ReactViews/Tools/Tool.tsx index 62bb2ba6824..665747b4ec0 100644 --- a/lib/ReactViews/Tools/Tool.tsx +++ b/lib/ReactViews/Tools/Tool.tsx @@ -11,7 +11,7 @@ import Terria from "../../Models/Terria"; import ViewerMode from "../../Models/ViewerMode"; import ViewState from "../../ReactViewModels/ViewState"; import MapNavigationItemController from "../../ViewModels/MapNavigation/MapNavigationItemController"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; interface ToolProps { toolName: string; diff --git a/lib/ReactViews/Tour/TourPortal.jsx b/lib/ReactViews/Tour/TourPortal.jsx index 6fa9c3785bb..d7a45815329 100644 --- a/lib/ReactViews/Tour/TourPortal.jsx +++ b/lib/ReactViews/Tour/TourPortal.jsx @@ -23,7 +23,7 @@ import { parseCustomMarkdownToReactWithOptions } from "../Custom/parseCustomMark import Caret from "../Generic/Caret"; import CloseButton from "../Generic/CloseButton"; import { useWindowSize } from "../Hooks/useWindowSize"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { applyTranslationIfExists } from "./../../Language/languageHelpers"; import { calculateLeftPosition, diff --git a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx index 5cc78d90fa4..5ef747bb44f 100644 --- a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx +++ b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx @@ -12,7 +12,7 @@ import Text, { TextSpan } from "../../Styled/Text"; import { ExplorerWindowElementName } from "../ExplorerWindow/ExplorerWindow"; import { useKeyPress } from "../Hooks/useKeyPress.js"; import VideoGuide from "../Map/Panels/HelpPanel/VideoGuide"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import { TourPortalDisplayName } from "../Tour/TourPortal"; import FadeIn from "../Transitions/FadeIn/FadeIn"; import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; diff --git a/lib/ReactViews/Map/Panels/TerrainSide.tsx b/lib/ReactViews/Workbench/TerrainSide.tsx similarity index 92% rename from lib/ReactViews/Map/Panels/TerrainSide.tsx rename to lib/ReactViews/Workbench/TerrainSide.tsx index d28ca65917a..b2191b56413 100644 --- a/lib/ReactViews/Map/Panels/TerrainSide.tsx +++ b/lib/ReactViews/Workbench/TerrainSide.tsx @@ -4,13 +4,13 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { useTheme } from "styled-components"; import SplitDirection from "terriajs-cesium/Source/Scene/SplitDirection"; -import Terria from "../../../Models/Terria"; -import ViewerMode from "../../../Models/ViewerMode"; -import Box from "../../../Styled/Box"; -import Checkbox from "../../../Styled/Checkbox/Checkbox"; -import { TextSpan } from "../../../Styled/Text"; -import { RawButton } from "./../../../Styled/Button"; -import { Spacing } from "./../../../Styled/Spacing"; +import Terria from "../../Models/Terria"; +import ViewerMode from "../../Models/ViewerMode"; +import Box from "../../Styled/Box"; +import Checkbox from "../../Styled/Checkbox/Checkbox"; +import { TextSpan } from "../../Styled/Text"; +import { RawButton } from "../../Styled/Button"; +import { Spacing } from "../../Styled/Spacing"; const sides = { left: "settingPanel.terrain.left", diff --git a/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx b/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx index 924354e1d26..578aa8528f2 100644 --- a/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx +++ b/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx @@ -11,7 +11,7 @@ import Box from "../../Styled/Box"; import { RawButton } from "../../Styled/Button"; import { GLYPHS, StyledIcon } from "../../Styled/Icon"; import Spacing from "../../Styled/Spacing"; -import TerrainSide from "../Map/Panels/TerrainSide"; +import TerrainSide from "./TerrainSide"; interface IWorkbenchSplitScreenProps { terria: Terria; diff --git a/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx b/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx index 986b1e74f09..9ea5d301d73 100644 --- a/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx +++ b/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { getName } from "../../ModelMixins/CatalogMemberMixin"; import { filterSelectableDimensions } from "../../Models/SelectableDimensions/SelectableDimensions"; import SelectableDimension from "../SelectableDimensions/SelectableDimension"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import WorkbenchItemControls, { hideAllControls } from "../Workbench/Controls/WorkbenchItemControls"; diff --git a/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx b/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx index f79856f8715..2866e06c45d 100644 --- a/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx +++ b/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx @@ -1,7 +1,7 @@ import React from "react"; import styled from "styled-components"; import { Portal } from "../StandardUserInterface/Portal"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { WorkflowPanelPortalId } from "./WorkflowPanel"; type PropsType = { @@ -24,10 +24,8 @@ const Container = styled.div<{ show: boolean }>` height: 100vh; width: ${(p) => p.theme.workflowPanelWidth}px; max-width: ${(p) => p.theme.workflowPanelWidth}px; - transition: all 0.25s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - visibility: ${(p) => (p.show ? "visible" : "hidden")}; margin-left: ${(p) => (p.show ? "0px" : `-${p.theme.workflowPanelWidth}px`)}; opacity: ${(p) => (p.show ? 1 : 0)}; diff --git a/lib/Styled/Text.tsx b/lib/Styled/Text.tsx index f0836f4a72b..0e58759baab 100644 --- a/lib/Styled/Text.tsx +++ b/lib/Styled/Text.tsx @@ -32,7 +32,7 @@ interface ITextWeight { export interface ITextPropsBase { displayBlock?: boolean; isLink?: boolean; - nunito?: boolean; + mono?: boolean; openSans?: boolean; breakWord?: boolean; uppercase?: boolean; @@ -68,6 +68,8 @@ export const Text = styled.div` // TODO: themeify family font-family: ${(props) => props.theme.fontBase}; + ${(props) => props.mono && `font-family: ${props.theme.fontMono};`} + ${(props) => props.breakWord && ` @@ -184,11 +186,6 @@ export const Text = styled.div` ` font-size: ${props.styledFontSize}; `} - ${(props) => - props.styledLineHeight && - ` - line-height: ${props.styledLineHeight}; - `} ${(props) => props.highlightLinks && diff --git a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts index a173ff3c2e6..b39d29200e6 100644 --- a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts +++ b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts @@ -53,4 +53,5 @@ declare interface FeatureDetection { isEdge(): boolean; isInternetExplorer(): boolean; internetExplorerVersion(): number[]; + chromeVersion(): number[]; } diff --git a/test/Map/StyledHtmlSpec.tsx b/test/Map/StyledHtmlSpec.tsx index b458f8784e5..e363ed5811e 100644 --- a/test/Map/StyledHtmlSpec.tsx +++ b/test/Map/StyledHtmlSpec.tsx @@ -5,7 +5,7 @@ import { ThemeProvider } from "styled-components"; import { act } from "react-dom/test-utils"; import Terria from "../../lib/Models/Terria"; import ViewState from "../../lib/ReactViewModels/ViewState"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import { StyledHtmlRaw } from "../../lib/ReactViews/Map/Panels/HelpPanel/StyledHtml"; import { TooltipWithButtonLauncher } from "../../lib/ReactViews/Generic/TooltipWrapper"; import registerCustomComponentTypes from "../../lib/ReactViews/Custom/registerCustomComponentTypes"; diff --git a/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts b/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts index 10a81afc216..05541195379 100644 --- a/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts +++ b/test/Models/Catalog/Ows/WebMapServiceCatalogItemSpec.ts @@ -375,6 +375,38 @@ describe("WebMapServiceCatalogItem", function () { }); }); + describe("rectangle - nested groups", () => { + const terria = new Terria(); + const wmsItem = new WebMapServiceCatalogItem("some-layer", terria); + + beforeEach(() => { + runInAction(() => { + wmsItem.setTrait(CommonStrata.definition, "url", "http://example.com"); + wmsItem.setTrait( + CommonStrata.definition, + "getCapabilitiesUrl", + "test/WMS/wms_nested_groups.xml" + ); + }); + }); + + it("correctly uses parent rectangle", async () => { + wmsItem.setTrait( + CommonStrata.definition, + "layers", + "landsat_barest_earth" + ); + + (await wmsItem.loadMetadata()).throwIfError(); + + // This will use the top level EX_GeographicBoundingBox ("Digital Earth Australia - OGC Web Services" Layer) + expect(wmsItem.rectangle.west).toBe(100); + expect(wmsItem.rectangle.east).toBe(160); + expect(wmsItem.rectangle.south).toBe(-50); + expect(wmsItem.rectangle.north).toBe(-10); + }); + }); + it("uses tileWidth and tileHeight", async function () { let wms: WebMapServiceCatalogItem; const terria = new Terria(); diff --git a/test/ReactViews/ClipboardSpec.tsx b/test/ReactViews/ClipboardSpec.tsx index eb239b7f848..4af48217ac2 100644 --- a/test/ReactViews/ClipboardSpec.tsx +++ b/test/ReactViews/ClipboardSpec.tsx @@ -2,7 +2,7 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import Clipboard from "../../lib/ReactViews/Clipboard"; import Input from "../../lib/Styled/Input"; import Button from "../../lib/Styled/Button"; diff --git a/test/ReactViews/DimensionSelectorSectionSpec.tsx b/test/ReactViews/DimensionSelectorSectionSpec.tsx index 9022477e954..073a2fc0500 100644 --- a/test/ReactViews/DimensionSelectorSectionSpec.tsx +++ b/test/ReactViews/DimensionSelectorSectionSpec.tsx @@ -15,7 +15,7 @@ import SelectableDimensions, { import Terria from "../../lib/Models/Terria"; import { SelectableDimensionGroup } from "../../lib/ReactViews/SelectableDimensions/Group"; import SelectableDimension from "../../lib/ReactViews/SelectableDimensions/SelectableDimension"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import SelectableDimensionSection from "../../lib/ReactViews/Workbench/Controls/SelectableDimensionSection"; import Checkbox from "../../lib/Styled/Checkbox"; import CatalogMemberTraits from "../../lib/Traits/TraitsClasses/CatalogMemberTraits"; diff --git a/test/ReactViews/Generic/PromptSpec.tsx b/test/ReactViews/Generic/PromptSpec.tsx index 2decc5f462f..31b7fa6f65b 100644 --- a/test/ReactViews/Generic/PromptSpec.tsx +++ b/test/ReactViews/Generic/PromptSpec.tsx @@ -5,7 +5,7 @@ import Terria from "../../../lib/Models/Terria"; import ViewState from "../../../lib/ReactViewModels/ViewState"; import { runInAction } from "mobx"; const Prompt: any = require("../../../lib/ReactViews/Generic/Prompt").default; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; import Caret from "../../../lib/ReactViews/Generic/Caret"; describe("HelpPrompt", function () { diff --git a/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx b/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx index 633f79e4040..d88e6da7f4f 100644 --- a/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx +++ b/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx @@ -5,10 +5,8 @@ import { act } from "react-dom/test-utils"; import Terria from "../../../../../lib/Models/Terria"; import ViewState from "../../../../../lib/ReactViewModels/ViewState"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface/StandardTheme"; -// import Compass from "../../../../../lib/ReactViews/Map/Navigation/Compass"; -const Compass: any = - require("../../../../../lib/ReactViews/Map/Navigation/Items/Compass").default; +import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface"; +import Compass from "../../../../../lib/ReactViews/Map/MapNavigation/Items/Compass/Compass"; import { StyledIcon } from "../../../../../lib/Styled/Icon"; describe("Compass", function () { diff --git a/test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx b/test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx similarity index 74% rename from test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx rename to test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx index 1450248f69b..f7883198777 100644 --- a/test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx +++ b/test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx @@ -1,10 +1,10 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; -import Terria from "../../../lib/Models/Terria"; -import ViewState from "../../../lib/ReactViewModels/ViewState"; -import GyroscopeGuidance from "../../../lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance"; -import MapIconButton from "../../../lib/ReactViews/MapIconButton/MapIconButton"; +import Terria from "../../../../../lib/Models/Terria"; +import ViewState from "../../../../../lib/ReactViewModels/ViewState"; +import { GyroscopeGuidance } from "../../../../../lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance"; +import MapIconButton from "../../../../../lib/ReactViews/MapIconButton/MapIconButton"; describe("GyroscopeGuidance", function () { let terria: Terria; diff --git a/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx b/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx index 803c40e90e5..884d9ffeaf5 100644 --- a/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx +++ b/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx @@ -2,7 +2,7 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface"; import Terria from "../../../../../lib/Models/Terria"; import ViewState from "../../../../../lib/ReactViewModels/ViewState"; const VideoGuide: any = diff --git a/test/ReactViews/MeasureToolSpec.jsx b/test/ReactViews/MeasureToolSpec.jsx index 326b3296c84..f79ced47844 100644 --- a/test/ReactViews/MeasureToolSpec.jsx +++ b/test/ReactViews/MeasureToolSpec.jsx @@ -5,7 +5,7 @@ import React from "react"; import Terria from "../../lib/Models/Terria"; import { getMountedInstance } from "./MoreShallowTools"; -import { MeasureTool } from "../../lib/ReactViews/Map/Navigation/MeasureTool"; +import { MeasureTool } from "../../lib/ReactViews/Map/MapNavigation/MeasureTool"; const Entity = require("terriajs-cesium/Source/DataSources/Entity.js").default; const Ellipsoid = require("terriajs-cesium/Source/Core/Ellipsoid.js").default; const ConstantPositionProperty = diff --git a/test/ReactViews/Preview/DescriptionSpec.tsx b/test/ReactViews/Preview/DescriptionSpec.tsx index 2d5873e46dc..fa1ec7c33d6 100644 --- a/test/ReactViews/Preview/DescriptionSpec.tsx +++ b/test/ReactViews/Preview/DescriptionSpec.tsx @@ -7,7 +7,7 @@ import Terria from "../../../lib/Models/Terria"; import updateModelFromJson from "../../../lib/Models/Definition/updateModelFromJson"; import WebMapServiceCatalogItem from "../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; import Description from "../../../lib/ReactViews/Preview/Description"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("DescriptionSpec", function () { let testRenderer: ReactTestRenderer; diff --git a/test/ReactViews/Search/BreadcrumbsSpec.tsx b/test/ReactViews/Search/BreadcrumbsSpec.tsx index 2eb3218fea6..f85ce9a5278 100644 --- a/test/ReactViews/Search/BreadcrumbsSpec.tsx +++ b/test/ReactViews/Search/BreadcrumbsSpec.tsx @@ -9,7 +9,7 @@ const DataCatalogTab: any = require("../../../lib/ReactViews/ExplorerWindow/Tabs/DataCatalogTab").default; import Icon from "../../../lib/Styled/Icon"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; import { runInAction } from "mobx"; describe("Breadcrumbs", function () { diff --git a/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx b/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx index 57862533302..f62f0fd3a6d 100644 --- a/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx +++ b/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx @@ -8,7 +8,7 @@ import SearchBoxAndResults, { SearchInDataCatalog } from "../../../lib/ReactViews/Search/SearchBoxAndResults"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("SearchBoxAndResults", function () { let terria: Terria; diff --git a/test/ReactViews/Search/SearchBoxSpec.tsx b/test/ReactViews/Search/SearchBoxSpec.tsx index ecf678efc20..bb60465a479 100644 --- a/test/ReactViews/Search/SearchBoxSpec.tsx +++ b/test/ReactViews/Search/SearchBoxSpec.tsx @@ -4,7 +4,7 @@ import { act } from "react-dom/test-utils"; import Terria from "../../../lib/Models/Terria"; import ViewState from "../../../lib/ReactViewModels/ViewState"; import { SearchBox } from "../../../lib/ReactViews/Search/SearchBox"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("SearchBox", function () { let terria: Terria; diff --git a/test/ReactViews/ShortReportSpec.tsx b/test/ReactViews/ShortReportSpec.tsx index c7bd4424564..7ea0022b6b4 100644 --- a/test/ReactViews/ShortReportSpec.tsx +++ b/test/ReactViews/ShortReportSpec.tsx @@ -8,7 +8,7 @@ import { import { ThemeProvider } from "styled-components"; import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; import Terria from "../../lib/Models/Terria"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import ShortReport from "../../lib/ReactViews/Workbench/Controls/ShortReport"; import Text from "../../lib/Styled/Text"; diff --git a/test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx b/test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx similarity index 96% rename from test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx rename to test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx index 14d8cab4a97..7bba0db2c75 100644 --- a/test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx +++ b/test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx @@ -3,7 +3,7 @@ import React from "react"; import { act } from "react-dom/test-utils"; import Terria from "../../../../lib/Models/Terria"; import ViewState from "../../../../lib/ReactViewModels/ViewState"; -import TrainerBar from "../../../../lib/ReactViews/Map/TrainerBar/TrainerBar"; +import TrainerBar from "../../../../lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar"; import Box from "../../../../lib/Styled/Box"; import { createWithContexts } from "../../withContext"; import TestHelpContent from "./test-help-content"; diff --git a/test/ReactViews/Map/TrainerBar/test-help-content.js b/test/ReactViews/StandardUserInterface/TrainerBar/test-help-content.js similarity index 100% rename from test/ReactViews/Map/TrainerBar/test-help-content.js rename to test/ReactViews/StandardUserInterface/TrainerBar/test-help-content.js diff --git a/test/ReactViews/WarningBoxSpec.tsx b/test/ReactViews/WarningBoxSpec.tsx index 842688bb523..ce62e67fee8 100644 --- a/test/ReactViews/WarningBoxSpec.tsx +++ b/test/ReactViews/WarningBoxSpec.tsx @@ -2,7 +2,7 @@ import { create, ReactTestInstance } from "react-test-renderer"; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import WarningBox from "../../lib/ReactViews/Preview/WarningBox"; import Terria from "../../lib/Models/Terria"; import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; diff --git a/test/ReactViews/withContext.tsx b/test/ReactViews/withContext.tsx index fcdcd03c866..35da0173e4d 100644 --- a/test/ReactViews/withContext.tsx +++ b/test/ReactViews/withContext.tsx @@ -2,8 +2,8 @@ import React from "react"; import { create, TestRendererOptions } from "react-test-renderer"; import { ThemeProvider } from "styled-components"; import ViewState from "../../lib/ReactViewModels/ViewState"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; -import { ViewStateProvider } from "../../lib/ReactViews/StandardUserInterface/ViewStateContext"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; +import { ViewStateProvider } from "../../lib/ReactViews/Context/ViewStateContext"; export function withThemeContext(node: React.ReactNode) { return {node}; diff --git a/wwwroot/test/WMS/wms_nested_groups.xml b/wwwroot/test/WMS/wms_nested_groups.xml index 070a6e8ceef..62a58e44d16 100644 --- a/wwwroot/test/WMS/wms_nested_groups.xml +++ b/wwwroot/test/WMS/wms_nested_groups.xml @@ -1,1175 +1,605 @@ - - - + WMS Digital Earth Australia - OGC Web Services - Digital Earth Australia OGC Web Services - - - - geomedian - - WOfS - - mangrove - - bare-earth - - NIDEM - - HLTC - - landsat - - australia - - time-series - - fractional-cover - + geomedian + WOfS + mangrove + bare-earth + NIDEM + HLTC + landsat + australia + time-series + fractional-cover - - - - - + - - - Digital Earth Australia - Geoscience Australia - - - - - - postal -
GPO Box 378
- Canberra - ACT - 2609 - Australia -
- - - +61 2 6249 9111 - - - - earth.observation@ga.gov.au - + + Digital Earth Australia + Geoscience Australia + + + postal +
GPO Box 378
+ Canberra + ACT + 2609 + Australia +
+ +61 2 6249 9111 + earth.observation@ga.gov.au
- - none © Commonwealth of Australia (Geoscience Australia) 2018. This product is released under the Creative Commons Attribution 4.0 International Licence. http://creativecommons.org/licenses/by/4.0/legalcode - 1 512 512 -
- - +
+ - - text/xml - - - - - - - - - - image/png - - - - - - - - - - application/json - - - - - - - - + + text/xml + + + + + + + + + + image/png + + + + + + + + + + application/json + + + + + + + + - - XML + XML - - - - - Digital Earth Australia - OGC Web Services - - + Digital Earth Australia - OGC Web Services + Digital Earth Australia OGC Web Services - - - - - EPSG:3857 - - EPSG:4326 - - EPSG:3577 - - EPSG:3111 - - - - - - - - + + EPSG:3857 + EPSG:4326 + EPSG:3577 + EPSG:3111 + + 100 + 160 + -50 + -10 + + Surface Reflectance - - - - - - - - - - - - ls8_nbart_geomedian_annual - Surface Reflectance 25m Annual Geomedian (Landsat 8) - + + + ls8_nbart_geomedian_annual + Surface Reflectance 25m Annual Geomedian (Landsat 8) + Data is only visible at higher resolutions; when zoomed-out the available area will be displayed as a shaded region. The surface reflectance geometric median (geomedian) is a pixel composite mosaic of a time series of earth observations. The value of a pixel in a an annual geomedian image is the statistical median of all observations for that pixel from a calendar year. -Annual mosaics are available for the following years: - -Landsat 8: 2013 to 2017; - -For more information, see http://pid.geoscience.gov.au/dataset/ga/120374 - -For service status information, see https://status.dea.ga.gov.au - - - +Annual mosaics are available for the following years:Landsat 8: 2013 to 2017;For more information, see http://pid.geoscience.gov.au/dataset/ga/120374For service status information, see https://status.dea.ga.gov.au + + WOfS - HLTC - landsat - time-series - mangrove - bare-earth - australia - geomedian - NIDEM - fractional-cover - - - + + 109.989859933428 156.101505058599 -45.2413329418709 -9.02727104242042 - - - - - - - - - - - - + + + + + + 2013-01-01,2014-01-01,2015-01-01,2016-01-01,2017-01-01,2018-01-01 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ls7_nbart_geomedian_annual - Surface Reflectance 25m Annual Geomedian (Landsat 7) - + + + + + + + + + + + + + + + ls7_nbart_geomedian_annual + Surface Reflectance 25m Annual Geomedian (Landsat 7) + Data is only visible at higher resolutions; when zoomed-out the available area will be displayed as a shaded region. The surface reflectance geometric median (geomedian) is a pixel composite mosaic of a time series of earth observations. The value of a pixel in a an annual geomedian image is the statistical median of all observations for that pixel from a calendar year. -Annual mosaics are available for the following years: - -Landsat 7: 2000 to 2017; - -For more information, see http://pid.geoscience.gov.au/dataset/ga/120374 - -For service status information, see https://status.dea.ga.gov.au - - - +Annual mosaics are available for the following years:Landsat 7: 2000 to 2017;For more information, see http://pid.geoscience.gov.au/dataset/ga/120374For service status information, see https://status.dea.ga.gov.au + + WOfS - HLTC - landsat - time-series - mangrove - bare-earth - australia - geomedian - NIDEM - fractional-cover - - - + + 109.989859933428 156.101505058599 -45.2413329418709 -9.02727104242042 - - - - - - - - - - - - + + + + + + 2000-01-01,2001-01-01,2002-01-01,2003-01-01,2004-01-01,2005-01-01,2006-01-01,2007-01-01,2008-01-01,2009-01-01,2010-01-01,2011-01-01,2012-01-01,2013-01-01,2014-01-01,2015-01-01,2016-01-01,2017-01-01,2018-01-01 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ls5_nbart_geomedian_annual - Surface Reflectance 25m Annual Geomedian (Landsat 5) - + + + + + + + + + + + + + + + ls5_nbart_geomedian_annual + Surface Reflectance 25m Annual Geomedian (Landsat 5) + Data is only visible at higher resolutions; when zoomed-out the available area will be displayed as a shaded region. The surface reflectance geometric median (geomedian) is a pixel composite mosaic of a time series of earth observations. The value of a pixel in a an annual geomedian image is the statistical median of all observations for that pixel from a calendar year. -Annual mosaics are available for the following years: - -Landsat 5: 1988 to 1999, 2004 to 2007, 2009 to 2011; - -For more information, see http://pid.geoscience.gov.au/dataset/ga/120374 - -For service status information, see https://status.dea.ga.gov.au - - - +Annual mosaics are available for the following years:Landsat 5: 1988 to 1999, 2004 to 2007, 2009 to 2011;For more information, see http://pid.geoscience.gov.au/dataset/ga/120374For service status information, see https://status.dea.ga.gov.au + + WOfS - HLTC - landsat - time-series - mangrove - bare-earth - australia - geomedian - NIDEM - fractional-cover - - - + + 109.989859933428 156.101505058599 -45.2413329418709 -9.02727104242042 - - - - - - - - - - - - + + + + + + 1988-01-01,1989-01-01,1990-01-01,1991-01-01,1992-01-01,1993-01-01,1994-01-01,1995-01-01,1996-01-01,1997-01-01,1998-01-01,1999-01-01,2004-01-01,2005-01-01,2006-01-01,2007-01-01,2009-01-01,2010-01-01,2011-01-01 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + Landsat-8 Barest Earth - - -A `weighted geometric median’ approach has been used to estimate the median surface reflectance of the barest state (i.e., least vegetation) observed through Landsat-8 OLI observations from 2013 to September 2018 to generate a six-band Landsat-8 Barest Earth pixel composite mosaic over the Australian continent. - -The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The weighted median approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy. -Reference: Dale Roberts, John Wilford, and Omar Ghattas (2018). Revealing the Australian Continent at its Barest, submitted. - -Mosaics are available for the following years: +A `weighted geometric median’ approach has been used to estimate the median surface reflectance of the barest state (i.e., least vegetation) observed through Landsat-8 OLI observations from 2013 to September 2018 to generate a six-band Landsat-8 Barest Earth pixel composite mosaic over the Australian continent.The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The weighted median approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy.Reference: Dale Roberts, John Wilford, and Omar Ghattas (2018). Revealing the Australian Continent at its Barest, submitted.Mosaics are available for the following years: Landsat 8: 2013 to 2017; - - - - - - - - - - ls8_barest_earth_mosaic - Landsat-8 Barest Earth 25m albers (Landsat-8) - -A `weighted geometric median’ approach has been used to estimate the median surface reflectance of the barest state (i.e., least vegetation) observed through Landsat-8 OLI observations from 2013 to September 2018 to generate a six-band Landsat-8 Barest Earth pixel composite mosaic over the Australian continent. -The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The weighted median approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy. - -Reference: Dale Roberts, John Wilford, and Omar Ghattas (2018). Revealing the Australian Continent at its Barest, submitted. - -Mosaics are available for the following years: - Landsat 8: 2013 to 2017; - -For service status information, see https://status.dea.ga.gov.au - - - + + + ls8_barest_earth_mosaic + Landsat-8 Barest Earth 25m albers (Landsat-8) + +A `weighted geometric median’ approach has been used to estimate the median surface reflectance of the barest state (i.e., least vegetation) observed through Landsat-8 OLI observations from 2013 to September 2018 to generate a six-band Landsat-8 Barest Earth pixel composite mosaic over the Australian continent.The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The weighted median approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy.Reference: Dale Roberts, John Wilford, and Omar Ghattas (2018). Revealing the Australian Continent at its Barest, submitted.Mosaics are available for the following years: + Landsat 8: 2013 to 2017;For service status information, see https://status.dea.ga.gov.au + + WOfS - HLTC - landsat - time-series - mangrove - bare-earth - australia - geomedian - NIDEM - fractional-cover - - - + + 109.989859933428 156.101505058599 -45.2413329418709 -9.02727104242042 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + Landsat 30+ Barest Earth - - -An estimate of the spectra of the barest state (i.e., least vegetation) observed from imagery of the Australian continent collected by the Landsat 5, 7, and 8 satellites over a period of more than 30 years (1983 - 2018). The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy. This product complements the Landsat-8 Barest Earth which is based on the same algorithm but just uses Landsat8 satellite imagery from 2013-2108. Landsat-8's OLI sensor provides improved signal-to-noise radiometric (SNR) performance quantised over a 12-bit dynamic range compared to the 8-bit dynamic range of Landsat-5 and Landsat-7 data. However the Landsat 30+ Barest Earth has a greater capacity to find the barest ground due to the greater temporal depth. Reference: Roberts, D., Wilford, J., Ghattas, O. (2019). Exposed Soil and Mineral Map of the Australian Continent Revealing the Land at its Barest. Nature Communications. Mosaics are available for the following years: Landsat 5 / Landsat 7 / Landsat 8 - 1983 to 2018; - +An estimate of the spectra of the barest state (i.e., least vegetation) observed from imagery of the Australian continent collected by the Landsat 5, 7, and 8 satellites over a period of more than 30 years (1983 - 2018). The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy. This product complements the Landsat-8 Barest Earth which is based on the same algorithm but just uses Landsat8 satellite imagery from 2013-2108. Landsat-8's OLI sensor provides improved signal-to-noise radiometric (SNR) performance quantised over a 12-bit dynamic range compared to the 8-bit dynamic range of Landsat-5 and Landsat-7 data. However the Landsat 30+ Barest Earth has a greater capacity to find the barest ground due to the greater temporal depth. Reference: Roberts, D., Wilford, J., Ghattas, O. (2019). Exposed Soil and Mineral Map of the Australian Continent Revealing the Land at its Barest. Nature Communications. Mosaics are available for the following years: Landsat 5 / Landsat 7 / Landsat 8 - 1983 to 2018; - - - - - - - - landsat_barest_earth - Landsat 30+ Barest Earth 25m albers (Combined Landsat) - -An estimate of the spectra of the barest state (i.e., least vegetation) observed from imagery of the Australian continent collected by the Landsat 5, 7, and 8 satellites over a period of more than 30 years (1983 - 2018). -The bands include BLUE (0.452 - 0.512), GREEN (0.533 - 0.590), RED, (0.636 - 0.673) NIR (0.851 - 0.879), SWIR1 (1.566 - 1.651) and SWIR2 (2.107 - 2.294) wavelength regions. The approach is robust to outliers (such as cloud, shadows, saturation, corrupted pixels) and also maintains the relationship between all the spectral wavelengths in the spectra observed through time. The product reduces the influence of vegetation and allows for more direct mapping of soil and rock mineralogy. -This product complements the Landsat-8 Barest Earth which is based on the same algorithm but just uses Landsat8 satellite imagery from 2013-2108. Landsat-8's OLI sensor provides improved signal-to-noise radiometric (SNR) performance quantised over a 12-bit dynamic range compared to the 8-bit dynamic range of Landsat-5 and Landsat-7 data. However the Landsat 30+ Barest Earth has a greater capacity to find the barest ground due to the greater temporal depth. -Reference: Roberts, D., Wilford, J., Ghattas, O. (2019). Exposed Soil and Mineral Map of the Australian Continent Revealing the Land at its Barest. Nature Communications. Mosaics are available for the following years: Landsat 5 / Landsat 7 / Landsat 8 - 1983 to 2018; For service status information, see https://status.dea.ga.gov.au - - - + + landsat_barest_earth + Landsat 30+ Barest Earth 25m albers (Combined Landsat) + +NOTE this layer has no EX_GeographicBoundingBox + + WOfS - HLTC - landsat - time-series - mangrove - bare-earth - australia - geomedian - NIDEM - fractional-cover - - - - 109.989859933428 - 156.101505058599 - -45.2413329418709 - -9.02727104242042 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - -
\ No newline at end of file + +