From a32aee48673a74b4ee6c679c979bec85f554851b Mon Sep 17 00:00:00 2001 From: Daniel Koch Date: Mon, 6 May 2024 13:16:23 +0200 Subject: [PATCH] feat: readd MapComponent, FloatingMapLogo and BackgroundLayerChooser --- package-lock.json | 8 +- package.json | 2 +- .../BackgroundLayerChooser.example.md | 99 +++--- .../BackgroundLayerChooser.less | 221 ++++++------ .../BackgroundLayerChooser.tsx | 321 +++++++++++++++--- .../BackgroundLayerPreview.less | 28 ++ .../BackgroundLayerPreview.tsx | 169 +++++++++ src/Button/CopyButton/CopyButton.example.md | 2 +- .../DeleteButton/DeleteButton.example.md | 2 +- src/Button/DrawButton/DrawButton.example.md | 2 +- .../GeoLocationButton.example.md | 2 +- .../MeasureButton/MeasureButton.example.md | 2 +- .../ModifyButton/ModifyButton.example.md | 2 +- src/Button/PrintButton/PrintButton.example.md | 2 +- .../RotationButton/RotationButton.example.md | 2 +- .../SelectFeaturesButton.example.md | 2 +- src/Button/ZoomButton/ZoomButton.example.md | 2 +- .../ZoomToExtentButton.example.md | 2 +- src/CircleMenu/CircleMenu.example.md | 2 +- .../AddWmsPanel/AddWmsPanel.example.md | 2 +- src/Context/MapContext/MapContext.example.md | 2 +- src/CoordinateInfo/CoordinateInfo.example.md | 2 +- .../CoordinateReferenceSystemCombo.example.md | 2 +- .../NominatimSearch.example.md | 2 +- src/Field/ScaleCombo/ScaleCombo.example.md | 2 +- .../WfsSearchField/WfsSearchField.example.md | 2 +- .../AgFeatureGrid/AgFeatureGrid.example.md | 2 +- src/Grid/FeatureGrid/FeatureGrid.example.md | 4 +- src/Hook/useDropTargetMap.example.md | 2 +- src/Hook/useMap.example.md | 2 +- src/LayerSwitcher/LayerSwitcher.example.md | 2 +- src/LayerSwitcher/LayerSwitcher.tsx | 2 +- src/LayerTree/LayerTree.example.md | 2 +- src/Legend/Legend.example.md | 2 +- .../FloatingMapLogo.example.md | 4 +- src/Map/FloatingMapLogo/FloatingMapLogo.less | 8 + .../FloatingMapLogo/FloatingMapLogo.spec.tsx | 30 ++ src/Map/FloatingMapLogo/FloatingMapLogo.tsx | 63 +++- src/Map/MapComponent/MapComponent.example.md | 53 ++- src/Map/MapComponent/MapComponent.spec.tsx | 29 ++ src/Map/MapComponent/MapComponent.tsx | 44 ++- .../LayerTransparencySlider.example.md | 2 +- .../MultiLayerSlider.example.md | 2 +- 43 files changed, 841 insertions(+), 298 deletions(-) create mode 100644 src/BackgroundLayerPreview/BackgroundLayerPreview.less create mode 100644 src/BackgroundLayerPreview/BackgroundLayerPreview.tsx create mode 100644 src/Map/FloatingMapLogo/FloatingMapLogo.less create mode 100644 src/Map/FloatingMapLogo/FloatingMapLogo.spec.tsx create mode 100644 src/Map/MapComponent/MapComponent.spec.tsx diff --git a/package-lock.json b/package-lock.json index 295111ec70..cd9fa3f2cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@terrestris/base-util": "^1.1.0", "@terrestris/ol-util": "^17.0.0", - "@terrestris/react-util": "^4.0.0", + "@terrestris/react-util": "^5.0.0-beta.0", "@types/geojson": "^7946.0.14", "@types/lodash": "^4.17.0", "ag-grid-community": "^31.1.1", @@ -5711,9 +5711,9 @@ } }, "node_modules/@terrestris/react-util": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@terrestris/react-util/-/react-util-4.0.0.tgz", - "integrity": "sha512-kcti+WT+/gRCrcwhdXkw/geGs3nv+FYCmLpb3oFvL/2TTfCesUNi/fXTT73hrugg5WWQA0b9V2UJGAX5LG+GuA==", + "version": "5.0.0-beta.0", + "resolved": "https://registry.npmjs.org/@terrestris/react-util/-/react-util-5.0.0-beta.0.tgz", + "integrity": "sha512-BvIEmE2Mlvp/RTF8VheQOGjDX4ljf9WylhFWRaxT6o4yITlxttwaqtzGLI0KyaT2AXPbY+hpszaFD8Ry+LvGbw==", "dependencies": { "@camptocamp/inkmap": "^1.4.0", "@terrestris/base-util": "^1.1.0", diff --git a/package.json b/package.json index e2293d9779..e752e00efc 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@terrestris/base-util": "^1.1.0", "@terrestris/ol-util": "^17.0.0", - "@terrestris/react-util": "^4.0.0", + "@terrestris/react-util": "^5.0.0-beta.0", "@types/geojson": "^7946.0.14", "@types/lodash": "^4.17.0", "ag-grid-community": "^31.1.1", diff --git a/src/BackgroundLayerChooser/BackgroundLayerChooser.example.md b/src/BackgroundLayerChooser/BackgroundLayerChooser.example.md index a456cd5adf..a13df049d4 100644 --- a/src/BackgroundLayerChooser/BackgroundLayerChooser.example.md +++ b/src/BackgroundLayerChooser/BackgroundLayerChooser.example.md @@ -2,7 +2,7 @@ The BackgroundLayerChooser ```jsx import BackgroundLayerChooser from '@terrestris/react-geo/dist/BackgroundLayerChooser/BackgroundLayerChooser'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import { useMap } from '@terrestris/react-util/dist/Hooks/useMap/useMap'; import OlLayerTile from 'ol/layer/Tile'; @@ -12,63 +12,56 @@ import OlSourceTileWMS from 'ol/source/TileWMS'; import OlView from 'ol/View'; import * as React from 'react'; -const layers = [ - new OlLayerTile({ - source: new OlSourceOsm(), - properties: { - name: 'OSM', - isBackgroundLayer: true - } - }), - new OlLayerTile({ - visible: false, - source: new OlSourceTileWMS({ - url: 'https://sgx.geodatenzentrum.de/wms_topplus_open', - params: { - LAYERS: 'web', +function BackgroundChooserExample() { + const layers = [ + new OlLayerTile({ + source: new OlSourceOsm(), + properties: { + name: 'OSM', + isBackgroundLayer: true } }), - properties: { - name: 'BKG', - isBackgroundLayer: true - } - }) -]; -const openlayersMap = new OlMap({ - view: new OlView({ - center: [801045, 6577113], - zoom: 9 - }), - layers -}); - -function ComponentToUseTheMap() { - const map = useMap(); - - // This is example specific and usually not needed - React.useEffect(() => { - map.setTarget('usemap-map'); - }, [map]); + new OlLayerTile({ + visible: false, + source: new OlSourceTileWMS({ + url: 'https://sgx.geodatenzentrum.de/wms_topplus_open', + params: { + LAYERS: 'web' + }, + attributions: '© Bundesamt für Kartographie und Geodäsie' + + `(${new Date().getFullYear()}), ` + + '' + + 'Datenquellen' + }), + properties: { + name: 'BKG', + isBackgroundLayer: true + } + }) + ]; - return ( - - ); -} + const map = new OlMap({ + view: new OlView({ + center: [801045, 6577113], + zoom: 9 + }), + layers + }); -function BackgroundChooserExample() { return ( - - - + + + + ); } diff --git a/src/BackgroundLayerChooser/BackgroundLayerChooser.less b/src/BackgroundLayerChooser/BackgroundLayerChooser.less index 11e2456e35..d5dbad4e16 100644 --- a/src/BackgroundLayerChooser/BackgroundLayerChooser.less +++ b/src/BackgroundLayerChooser/BackgroundLayerChooser.less @@ -1,90 +1,108 @@ .bg-layer-chooser { + position: absolute; + bottom: 20px; + right: 5px; + z-index: 10; + display: flex; align-items: center; justify-content: flex-end; - &.moved { - transition: 400ms; + .change-bg-btn { + width: 22px; + height: 64px; + z-index: 3; + border: 1px solid #808080; + // suppress border on hover and focus + border-right: none !important; + border-bottom-right-radius: 0; + border-top-right-radius: 0; + border-radius: 0; + + &.toggled { + border-left: none; + } + } + + .layer-cards { + display: flex; + gap: 10px; + padding: 5px; + background-color: #fff; + border: solid 1px #808080; + border-radius: 4px; } .no-background { - height: 128px; + cursor: pointer; + margin: auto 0; width: 128px; - padding-bottom: 15px; + height: 128px; + position: relative; - span.layer-title { - position: absolute; - bottom: 0; - right: 10px; + &:hover { + outline: 2px solid #2f4f4f; } - } - .bg-preview { - position: relative; - width: 140px; - height: 140px; + .no-background-preview { + padding: 5%; + padding-bottom: 25px; + height: 100%; + width: 100%; - span.layer-title { - position: absolute; - bottom: 0; - margin: 5px; - background: var(--ant-primary-color); - color: #fff; - font-weight: bolder; - text-align: center; - width: 128px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - padding: 0 4px; + svg { + height: 100%; + width: 100%; + } } - span.layer-title-no-background { + .layer-title { position: absolute; + left: 0; bottom: 0; - margin: 5px; - background: var(--ant-primary-color); - color: #fff; - font-weight: bolder; + background: #fff; + color: #000; text-align: center; - width: 128px; + width: 100%; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; - left: 0px; + padding: 0 4px; } - .no-background-preview { - border: solid 1px var(--ant-primary-color); - border-radius: 4px; - box-shadow: 0 6px 12px rgb(0 0 0 / 18%), 0 -6px 12px rgb(0 0 0 / 18%); - background-color: var(--ant-primary-1); - padding: 5%; - height: auto; - width: auto; - color: #fff; - font-size: 3em; + &.selected { + span.layer-title { + outline: 2px solid #2f4f4f; + font-weight: bold; + } } + } - #overview-map { + .bg-preview { + position: relative; + width: 140px; + height: 140px; - width: 140px; - height: 140px; + #overview-map { + height: 100%; + width: 100%; .react-geo-bg-layer-chooser-overviewmap { - bottom: unset; - left: unset; - right: unset; - top: unset; - border: solid 1px var(--ant-primary-color); + height: 100%; + width: 100%; + border: solid 1px #808080; border-radius: 4px; box-shadow: 0 6px 12px rgb(0 0 0 / 18%), 0 -6px 12px rgb(0 0 0 / 18%); - background-color: var(--ant-primary-1); + background-color: #fff; .ol-overviewmap-map { border: none; - width: 140px; - height: 140px; + width: 100%; + height: 100%; + + .ol-viewport { + border-radius: 4px; + } } .ol-overviewmap-box { @@ -92,85 +110,44 @@ outline: 2px solid blue; } .ol-overviewmap-box:before { - content: " "; + content: ' '; position: absolute; - outline: 2px dashed white; + outline: 2px dashed #fff; width: 100%; height: 100%; } } } - } - - button.change-bg-btn { - width: 22px; - height: 64px; - z-index: 3; - border: 1px solid var(--ant-primary-color); - // suppress border on hover and focus - border-right: none !important; - border-bottom-right-radius: 0; - border-top-right-radius: 0; - - &.toggled { - border-radius: 0; - border-left: none; - } - } - -} - -// styling for preview cards -.layer-cards { - display: flex; - gap: 10px; - padding: 5px; - background-color: var(--ant-primary-1); - border: solid 1px var(--ant-primary-color); - border-radius: 4px; - transition: 400ms; - - .layer-preview { - cursor: pointer; - margin: auto 0; - - &:hover { - outline: 2px solid var(--ant-primary-color-active); - } - - &.selected { - .ant-spin-container { - img, - div.no-preview, - span.layer-title { - outline: 2px solid var(--ant-primary-color-active); - font-weight: bold; - } - } - } - - .ant-spin-container { - display: flex; - flex-direction: column; - - canvas { - outline: solid 1px var(--ant-primary-color ); - } + .no-background-preview { + border: solid 1px #808080; + border-radius: 4px; + box-shadow: 0 6px 12px rgb(0 0 0 / 18%), 0 -6px 12px rgb(0 0 0 / 18%); + background-color: #fff; + padding: 5%; + padding-bottom: 25px; + height: 100%; + width: 100%; - span.layer-title { - position: absolute; - bottom: 0; - background: var(--ant-primary-color); - color: #fff; - text-align: center; + svg { + height: 100%; width: 100%; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - padding: 0 4px; } } + span.layer-title { + position: absolute; + bottom: 1px; + left: 1px; + background:rgba(255, 255, 255, 0.8); + border-radius: 0 0 4px 4px; + color: #000; + font-weight: bolder; + text-align: center; + width: calc(100% - 2px);; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } } } diff --git a/src/BackgroundLayerChooser/BackgroundLayerChooser.tsx b/src/BackgroundLayerChooser/BackgroundLayerChooser.tsx index c545cb4697..6df8631770 100644 --- a/src/BackgroundLayerChooser/BackgroundLayerChooser.tsx +++ b/src/BackgroundLayerChooser/BackgroundLayerChooser.tsx @@ -1,77 +1,292 @@ import './BackgroundLayerChooser.less'; import { + faBan, faChevronLeft, - faChevronRight, -} from '@fortawesome/free-solid-svg-icons'; + faChevronRight} from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import BackgroudLayerChooserBase, { - BackgroundLayerButtonProps -} from '@terrestris/react-util/dist/Components/BackgroundLayerChooser/BackgroundLayerChooser'; -import { - BackgroundLayerLoadingMaskProps -} from '@terrestris/react-util/dist/Components/BackgroundLayerPreview/BackgroundLayerPreview'; -import Spin from 'antd/lib/spin'; +import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; +import OlOverviewMap from 'ol/control/OverviewMap'; import OlLayerBase from 'ol/layer/Base'; +import OlLayerGroup from 'ol/layer/Group'; +import OlLayerImage from 'ol/layer/Image'; import OlLayer from 'ol/layer/Layer'; -import React from 'react'; +import OlLayerTile from 'ol/layer/Tile'; +import { ObjectEvent } from 'ol/Object'; +import OlSourceImageWMS from 'ol/source/ImageWMS'; +import OlSourceOSM from 'ol/source/OSM'; +import OlSourceTileWMS from 'ol/source/TileWMS'; +import { getUid } from 'ol/util'; +import OlView from 'ol/View'; +import { apply as applyMapboxStyle } from 'ol-mapbox-style'; +import React, { + useEffect, + useRef, + useState +} from 'react'; +import BackgroundLayerPreview from '../BackgroundLayerPreview/BackgroundLayerPreview'; import SimpleButton from '../Button/SimpleButton/SimpleButton'; export type BackgroundLayerChooserProps = { + /** + * Array of layers to be displayed in the BackgroundLayerChooser. + */ layers: OlLayer[]; - tooltip?: string; + /** + * Adds a button that clears the backgroundlayer. + */ + allowEmptyBackground?: boolean; + /** + * Filters the backgroundlayers by a function. + */ backgroundLayerFilter?: (layer: OlLayerBase) => boolean; + /** + * Select a Layer that should be active initially. + */ + initiallySelectedLayer?: OlLayer; + /** + * Customize the tooltip. + */ + buttonTooltip?: string; + /** + * Sets the title of the No-Background Button + */ + noBackgroundTitle?: string; }; -const SwitcherButton: React.FC = ({ - layerOptionsVisible, - onClick, - buttonTooltip +/** + * This component supports TileWMS and ImageWMS layers. Besides that, mapbox vector tile layers are + * also supported in a limited way: + * + * * you'll need to render the vector tile layer inside of a group layer + * * the group layer needs to have a property isVectorTile set to true + * * the group layer needs to have a property url pointing to the json description + */ +export const BackgroundLayerChooser: React.FC = ({ + layers, + allowEmptyBackground = false, + buttonTooltip = 'Change background layer', + initiallySelectedLayer, + noBackgroundTitle = 'No Background', + backgroundLayerFilter = (l: OlLayerBase) => !!l.get('isBackgroundLayer') }) => { - return ( - : - + const map = useMap(); + + const [zoom, setZoom] = useState(map?.getView()?.getZoom()); + const [center, setCenter] = useState(map?.getView()?.getCenter()); + const [layerOptionsVisible, setLayerOptionsVisible] = useState(false); + const [selectedLayer, setSelectedLayer] = useState(); + const [isBackgroundImage, setIsBackgroundImage] = useState(false); + + const mapTarget = useRef(null); + + useEffect(() => { + if (map && layerOptionsVisible) { + setCenter(map.getView().getCenter()); + setZoom(map.getView().getZoom()); + const centerListener = (evt: ObjectEvent) => { + setCenter(evt.target.getCenter()); + }; + const resolutionListener = (evt: ObjectEvent) => { + setZoom(evt.target.getZoom()); + }; + map.getView().on('change:center', centerListener); + map.getView().on('change:resolution', resolutionListener); + return () => { + map.getView().un('change:center', centerListener); + map.getView().un('change:resolution', resolutionListener); + }; + } + return undefined; + }, [map, layerOptionsVisible]); + + useEffect(() => { + const activeLayerCand = layers.find(l => l.getVisible()); + + if (!initiallySelectedLayer) { + setSelectedLayer(activeLayerCand as OlLayer); + } + }, [initiallySelectedLayer, layers]); + + useEffect(() => { + if (!selectedLayer || !map) { + return undefined; + } + const selectedLayerSource = selectedLayer.getSource(); + + let ovLayer: OlLayer | OlLayerGroup | null = null; + + if (selectedLayer instanceof OlLayerTile) { + let newSource: OlSourceOSM | OlSourceTileWMS | null = null; + + if (selectedLayerSource instanceof OlSourceTileWMS) { + newSource = new OlSourceTileWMS({ + url: selectedLayerSource.getUrls()?.[0], + params: selectedLayerSource.getParams(), + tileLoadFunction: selectedLayerSource.getTileLoadFunction() + }); + } else if (selectedLayerSource instanceof OlSourceOSM) { + newSource = new OlSourceOSM(); } - onClick={onClick} - /> - ); -}; -const LoadingMask: React.FC = ({ - loading, - children -}) => { - return ( - - {children} - - ); -}; + if (newSource) { + ovLayer = new OlLayerTile({ + source: newSource + }); + } + } else if (selectedLayer instanceof OlLayerImage) { + let newSource: OlSourceImageWMS | null = null; -export const BackgroundLayerChooser: React.FC = ({ - tooltip, - layers, - backgroundLayerFilter -}) => { + if (selectedLayerSource instanceof OlSourceImageWMS) { + newSource = new OlSourceImageWMS({ + url: selectedLayerSource.getUrl(), + params: selectedLayerSource.getParams(), + imageLoadFunction: selectedLayerSource.getImageLoadFunction() + }); + } + + if (newSource) { + ovLayer = new OlLayerImage({ + source: selectedLayer.getSource() + }); + } + } else if (selectedLayer instanceof OlLayerGroup) { + if (selectedLayer.get('isVectorTile')) { + ovLayer = new OlLayerGroup(); + applyMapboxStyle(ovLayer, selectedLayer.get('url')); + } else { + ovLayer = new OlLayerGroup({ + layers: selectedLayer.getLayers() + }); + } + } + + if (ovLayer && mapTarget.current) { + const overViewControl = new OlOverviewMap({ + collapsible: false, + target: mapTarget.current, + className: 'ol-overviewmap react-geo-bg-layer-chooser-overviewmap', + layers: [ovLayer], + view: new OlView({ + projection: map.getView().getProjection() + }) + }); + + map.addControl(overViewControl); + + return () => { + map.removeControl(overViewControl); + }; + } + + return undefined; + }, [selectedLayer, map]); + + const onLayerSelect = (layer: OlLayer) => { + setLayerOptionsVisible(false); + setSelectedLayer(layer); + setIsBackgroundImage(false); + }; return ( - +
+ { + layerOptionsVisible && ( +
+ { + layers.map(layer => ( + onLayerSelect(l)} + layer={layer} + backgroundLayerFilter={backgroundLayerFilter} + zoom={zoom} + center={center} + /> + )) + } + { + allowEmptyBackground && +
{ + selectedLayer?.setVisible(false); + }} + onMouseLeave={() => { + selectedLayer?.setVisible(true); + }} + onClick={() => { + selectedLayer?.setVisible(false); + setSelectedLayer(undefined); + setLayerOptionsVisible(false); + setIsBackgroundImage(true); + }} + > +
+ +
+ + {noBackgroundTitle} + +
+ } +
+ ) + } + : + + } + onClick={() => setLayerOptionsVisible(!layerOptionsVisible)} + /> +
+ { + !isBackgroundImage ? +
: +
+ +
+ } + { + selectedLayer ? + + {selectedLayer.get('name')} + : + + {noBackgroundTitle} + + } +
+
); }; diff --git a/src/BackgroundLayerPreview/BackgroundLayerPreview.less b/src/BackgroundLayerPreview/BackgroundLayerPreview.less new file mode 100644 index 0000000000..40de5eb350 --- /dev/null +++ b/src/BackgroundLayerPreview/BackgroundLayerPreview.less @@ -0,0 +1,28 @@ +.layer-preview { + cursor: pointer; + margin: auto 0; + + &:hover { + outline: 2px solid #2f4f4f; + } + + &.selected { + .layer-title { + outline: 2px solid #2f4f4f; + font-weight: bold; + } + } + + .layer-title { + position: absolute; + bottom: 0; + background: #fff; + color: #000; + text-align: center; + width: 100%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + padding: 0 4px; + } +} diff --git a/src/BackgroundLayerPreview/BackgroundLayerPreview.tsx b/src/BackgroundLayerPreview/BackgroundLayerPreview.tsx new file mode 100644 index 0000000000..856e66bdbf --- /dev/null +++ b/src/BackgroundLayerPreview/BackgroundLayerPreview.tsx @@ -0,0 +1,169 @@ +import './BackgroundLayerPreview.less'; + +import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; +import { Spin } from 'antd'; +import { Coordinate } from 'ol/coordinate'; +import OlLayerBase from 'ol/layer/Base'; +import OlLayerImage from 'ol/layer/Image'; +import OlLayer from 'ol/layer/Layer'; +import OlLayerTile from 'ol/layer/Tile'; +import OlMap from 'ol/Map'; +import { getUid } from 'ol/util'; +import OlView from 'ol/View'; +import React, { + useEffect, + useMemo, + useState +} from 'react'; + +import MapComponent from '../Map/MapComponent/MapComponent'; + +export type BackgroundLayerPreviewProps = { + width?: number; + height?: number; + layer: OlLayer; + activeLayer?: OlLayer; + onClick: (l: OlLayer) => void; + zoom?: number; + center?: Coordinate; + backgroundLayerFilter: (l: OlLayerBase) => boolean; +}; + +export const BackgroundLayerPreview: React.FC = ({ + layer, + activeLayer, + width = 128, + height = 128, + onClick, + zoom, + center, + backgroundLayerFilter +}) => { + + const [loading, setLoading] = useState(false); + + const mainMap = useMap(); + + const previewLayer = useMemo(() => { + if (layer instanceof OlLayerTile) { + return new OlLayerTile({ + source: layer.getSource() + }); + } else if (layer instanceof OlLayerImage) { + return new OlLayerImage({ + source: layer.getSource() + }); + } + return undefined; + }, [layer]); + + const previewMap = useMemo(() => { + return new OlMap({ + view: new OlView({ + projection: mainMap?.getView().getProjection(), + resolutions: mainMap?.getView().getResolutions(), + center: center, + zoom: zoom + }), + controls: [], + interactions: [], + layers: previewLayer && [previewLayer] + }); + }, [center, mainMap, previewLayer, zoom]); + + useEffect(() => { + const setTrue = () => setLoading(true); + const setFalse = () => setLoading(false); + previewMap.on('loadstart', setTrue); + previewMap.on('loadend', setFalse); + + return () => { + previewMap.un('loadstart', setTrue); + previewMap.un('loadend', setFalse); + }; + }, [previewMap]); + + useEffect(() => { + if (zoom) { + previewMap.getView().setZoom(zoom); + } + if (center) { + previewMap.getView().setCenter(center); + } + }, [zoom, center, previewMap]); + + const getBgLayersFromMap = (): OlLayer[] => { + return mainMap?.getLayerGroup() + .getLayers() + .getArray() + .filter(backgroundLayerFilter) as OlLayer[] || []; + }; + + const updateBgLayerVisibility = (evt: React.MouseEvent) => { + const target = evt?.currentTarget; + const layerId = target?.dataset?.uid; + + if (!layerId) { + return; + } + + const newBgLayer = mainMap?.getLayerGroup() + .getLayers() + .getArray() + .find(l => getUid(l) === layerId); + + if (!newBgLayer) { + return; + } + + getBgLayersFromMap().forEach(l => l.setVisible(false)); + newBgLayer.setVisible(true); + + if (evt.type === 'click') { + onClick(newBgLayer as OlLayer); + } + }; + + const restoreBgLayerVisibility = () => { + getBgLayersFromMap().forEach(l => l.setVisible(false)); + activeLayer?.setVisible(true); + }; + + let isActive = false; + const uid = getUid(layer); + if (activeLayer) { + const activeUid = getUid(activeLayer); + isActive = uid === activeUid; + } + + return ( +
+ + + + {layer.get('name')} + + +
+ ); +}; + +export default BackgroundLayerPreview; diff --git a/src/Button/CopyButton/CopyButton.example.md b/src/Button/CopyButton/CopyButton.example.md index 326949d8d8..b839aeb3cc 100644 --- a/src/Button/CopyButton/CopyButton.example.md +++ b/src/Button/CopyButton/CopyButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the CopyButton. ```jsx import CopyButton from '@terrestris/react-geo/dist/Button/CopyButton/CopyButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import {DigitizeUtil} from '@terrestris/react-util/dist/Util/DigitizeUtil'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; diff --git a/src/Button/DeleteButton/DeleteButton.example.md b/src/Button/DeleteButton/DeleteButton.example.md index fafb0af1dc..84e803435b 100644 --- a/src/Button/DeleteButton/DeleteButton.example.md +++ b/src/Button/DeleteButton/DeleteButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the DeleteButton. ```jsx import { DeleteButton } from '@terrestris/react-geo/dist/Button/DeleteButton/DeleteButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext' import { DigitizeUtil } from '@terrestris/react-util/dist/Util/DigitizeUtil'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; diff --git a/src/Button/DrawButton/DrawButton.example.md b/src/Button/DrawButton/DrawButton.example.md index 21b4f425a3..1077e3ee94 100644 --- a/src/Button/DrawButton/DrawButton.example.md +++ b/src/Button/DrawButton/DrawButton.example.md @@ -3,7 +3,7 @@ This demonstrates the use of the DrawButton. ```jsx import DrawButton from '@terrestris/react-geo/dist/Button/DrawButton/DrawButton'; import ToggleGroup from '@terrestris/react-geo/dist/Button/ToggleGroup/ToggleGroup'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext' import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Button/GeoLocationButton/GeoLocationButton.example.md b/src/Button/GeoLocationButton/GeoLocationButton.example.md index d5feac115b..cb106038bb 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.example.md +++ b/src/Button/GeoLocationButton/GeoLocationButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the GeoLocation button. ```jsx import GeoLocationButton from '@terrestris/react-geo/dist/Button/GeoLocationButton/GeoLocationButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Button/MeasureButton/MeasureButton.example.md b/src/Button/MeasureButton/MeasureButton.example.md index e797cfc146..bffcff14e8 100644 --- a/src/Button/MeasureButton/MeasureButton.example.md +++ b/src/Button/MeasureButton/MeasureButton.example.md @@ -3,7 +3,7 @@ This demonstrates the use of MeasureButton with different measure types. ```jsx import MeasureButton from '@terrestris/react-geo/dist/Button/MeasureButton/MeasureButton'; import ToggleGroup from '@terrestris/react-geo/dist/Button/ToggleGroup/ToggleGroup'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Button/ModifyButton/ModifyButton.example.md b/src/Button/ModifyButton/ModifyButton.example.md index 04d9c98521..1aeae45e6f 100644 --- a/src/Button/ModifyButton/ModifyButton.example.md +++ b/src/Button/ModifyButton/ModifyButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the ModifyButton. ```jsx import {ModifyButton} from '@terrestris/react-geo/dist/Button/ModifyButton/ModifyButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext' import {DigitizeUtil} from '@terrestris/react-util/dist/Util/DigitizeUtil'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; diff --git a/src/Button/PrintButton/PrintButton.example.md b/src/Button/PrintButton/PrintButton.example.md index d9747f39a8..e7202a3ffd 100644 --- a/src/Button/PrintButton/PrintButton.example.md +++ b/src/Button/PrintButton/PrintButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the PrintButton. ```jsx import PrintButton from '@terrestris/react-geo/dist/Button/PrintButton/PrintButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext' import { Progress } from 'antd'; import {getTopLeft, getWidth} from 'ol/extent'; diff --git a/src/Button/RotationButton/RotationButton.example.md b/src/Button/RotationButton/RotationButton.example.md index 1197aff32a..e9e52b47c3 100644 --- a/src/Button/RotationButton/RotationButton.example.md +++ b/src/Button/RotationButton/RotationButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the RotationButton ```jsx import RotationButton from '@terrestris/react-geo/dist/Button/RotationButton/RotationButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Button/SelectFeaturesButton/SelectFeaturesButton.example.md b/src/Button/SelectFeaturesButton/SelectFeaturesButton.example.md index 1b5fc88f62..ecaebd7b4e 100644 --- a/src/Button/SelectFeaturesButton/SelectFeaturesButton.example.md +++ b/src/Button/SelectFeaturesButton/SelectFeaturesButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of the SelectFeaturesButton. ```jsx import SelectFeaturesButton from '@terrestris/react-geo/dist/Button/SelectFeaturesButton/SelectFeaturesButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext' import OlFormatGeoJSON from 'ol/format/GeoJSON'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/Button/ZoomButton/ZoomButton.example.md b/src/Button/ZoomButton/ZoomButton.example.md index 1f0644fdb1..9eded47cad 100644 --- a/src/Button/ZoomButton/ZoomButton.example.md +++ b/src/Button/ZoomButton/ZoomButton.example.md @@ -2,7 +2,7 @@ This example demonstrates some uses of of the `ZoomButton` to zoom in and out of ```jsx import ZoomButton from '@terrestris/react-geo/dist/Button/ZoomButton/ZoomButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Button/ZoomToExtentButton/ZoomToExtentButton.example.md b/src/Button/ZoomToExtentButton/ZoomToExtentButton.example.md index 681d4f50f7..a6b7038dc1 100644 --- a/src/Button/ZoomToExtentButton/ZoomToExtentButton.example.md +++ b/src/Button/ZoomToExtentButton/ZoomToExtentButton.example.md @@ -2,7 +2,7 @@ This demonstrates the use of ZoomToExtentButton. ```jsx import ZoomToExtentButton from '@terrestris/react-geo/dist/Button/ZoomToExtentButton/ZoomToExtentButton'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/CircleMenu/CircleMenu.example.md b/src/CircleMenu/CircleMenu.example.md index 963a785168..ec453b91c5 100644 --- a/src/CircleMenu/CircleMenu.example.md +++ b/src/CircleMenu/CircleMenu.example.md @@ -7,7 +7,7 @@ import { faBullhorn,faChartLine, faLink, faPencil, faThumbsUp } from '@fortaweso import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import SimpleButton from '@terrestris/react-geo/dist/Button/SimpleButton/SimpleButton'; import CircleMenu from '@terrestris/react-geo/dist/CircleMenu/CircleMenu'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import OlFeature from 'ol/Feature'; import OlGeomPoint from 'ol/geom/Point'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/Container/AddWmsPanel/AddWmsPanel.example.md b/src/Container/AddWmsPanel/AddWmsPanel.example.md index 8db47eb049..4f194e6974 100644 --- a/src/Container/AddWmsPanel/AddWmsPanel.example.md +++ b/src/Container/AddWmsPanel/AddWmsPanel.example.md @@ -6,7 +6,7 @@ An `AddWmsPanel` shows a list of the parsed layers and each checked layer (or th import CapabilitiesUtil from '@terrestris/ol-util/dist/CapabilitiesUtil/CapabilitiesUtil'; import SimpleButton from '@terrestris/react-geo/dist/Button/SimpleButton/SimpleButton'; import AddWmsPanel from '@terrestris/react-geo/dist/Container/AddWmsPanel/AddWmsPanel'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; import { WmsLayer } from '@terrestris/react-util/dist/Util/typeUtils'; diff --git a/src/Context/MapContext/MapContext.example.md b/src/Context/MapContext/MapContext.example.md index f2d657582a..3019b7af6d 100644 --- a/src/Context/MapContext/MapContext.example.md +++ b/src/Context/MapContext/MapContext.example.md @@ -4,7 +4,7 @@ with [react 16.3](https://reactjs.org/docs/context.html). If you are using function-components head over to the `useMap` example in the "HOOKS" section. ```jsx -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/CoordinateInfo/CoordinateInfo.example.md b/src/CoordinateInfo/CoordinateInfo.example.md index ee9ffdaaf1..dcf32dcc0d 100644 --- a/src/CoordinateInfo/CoordinateInfo.example.md +++ b/src/CoordinateInfo/CoordinateInfo.example.md @@ -2,7 +2,7 @@ import { faCopy } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import CoordinateInfo from '@terrestris/react-geo/dist/CoordinateInfo/CoordinateInfo'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import { Button, diff --git a/src/Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo.example.md b/src/Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo.example.md index b1e72ed748..f8f52f180b 100644 --- a/src/Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo.example.md +++ b/src/Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo.example.md @@ -3,7 +3,7 @@ This demonstrates the usage of the CoordinateReferenceSystemCombo. ```jsx import CoordinateReferenceSystemCombo from '@terrestris/react-geo/dist/Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import { applyTransform } from 'ol/extent'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/Field/NominatimSearch/NominatimSearch.example.md b/src/Field/NominatimSearch/NominatimSearch.example.md index 8fea82e420..65d2203821 100644 --- a/src/Field/NominatimSearch/NominatimSearch.example.md +++ b/src/Field/NominatimSearch/NominatimSearch.example.md @@ -2,7 +2,7 @@ This demonstrates the usage of the NominatimSearch. ```jsx import NominatimSearch from '@terrestris/react-geo/dist/Field/NominatimSearch/NominatimSearch'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Field/ScaleCombo/ScaleCombo.example.md b/src/Field/ScaleCombo/ScaleCombo.example.md index e19e7fc5ad..7076d5bd4f 100644 --- a/src/Field/ScaleCombo/ScaleCombo.example.md +++ b/src/Field/ScaleCombo/ScaleCombo.example.md @@ -2,7 +2,7 @@ This is a example containing a map component and a scale combo ```jsx import ScaleCombo from '@terrestris/react-geo/dist/Field/ScaleCombo/ScaleCombo'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Field/WfsSearchField/WfsSearchField.example.md b/src/Field/WfsSearchField/WfsSearchField.example.md index d58aa8464a..306102bcc5 100644 --- a/src/Field/WfsSearchField/WfsSearchField.example.md +++ b/src/Field/WfsSearchField/WfsSearchField.example.md @@ -4,7 +4,7 @@ Type a country name in its own language… ```jsx import WfsSearch from '@terrestris/react-geo/dist/Field/WfsSearchField/WfsSearchField'; import AgFeatureGrid from '@terrestris/react-geo/dist/Grid/AgFeatureGrid/AgFeatureGrid'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/Grid/AgFeatureGrid/AgFeatureGrid.example.md b/src/Grid/AgFeatureGrid/AgFeatureGrid.example.md index 0b9213ba54..c2f78423b5 100644 --- a/src/Grid/AgFeatureGrid/AgFeatureGrid.example.md +++ b/src/Grid/AgFeatureGrid/AgFeatureGrid.example.md @@ -2,7 +2,7 @@ This example demonstrates the usage of the AgFeatureGrid: ```jsx import AgFeatureGrid from '@terrestris/react-geo/dist/Grid/AgFeatureGrid/AgFeatureGrid'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/Grid/FeatureGrid/FeatureGrid.example.md b/src/Grid/FeatureGrid/FeatureGrid.example.md index 5c6b5dd2ca..576861e44a 100644 --- a/src/Grid/FeatureGrid/FeatureGrid.example.md +++ b/src/Grid/FeatureGrid/FeatureGrid.example.md @@ -2,7 +2,7 @@ This example demonstrates the usage of the FeatureGrid: ```jsx import FeatureGrid from '@terrestris/react-geo/dist/Grid/FeatureGrid/FeatureGrid'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; import OlLayerTile from 'ol/layer/Tile'; @@ -85,7 +85,7 @@ An example with a remote feature source. ```jsx import UrlUtil from '@terrestris/base-util/dist/UrlUtil/UrlUtil'; import FeatureGrid from '@terrestris/react-geo/dist/Grid/FeatureGrid/FeatureGrid'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import Input from 'antd/lib/input'; import OlFormatGeoJSON from 'ol/format/GeoJSON'; diff --git a/src/Hook/useDropTargetMap.example.md b/src/Hook/useDropTargetMap.example.md index b051b70b68..5c0c89448f 100644 --- a/src/Hook/useDropTargetMap.example.md +++ b/src/Hook/useDropTargetMap.example.md @@ -2,7 +2,7 @@ This example shows the usage of the DropTargetMap HOC by use of the onDropAware function. ```jsx -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import useDropTargetMap from '@terrestris/react-util/dist/Hooks/useDropTargetMap/useDropTargetMap'; import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; diff --git a/src/Hook/useMap.example.md b/src/Hook/useMap.example.md index b27b1d4cfc..7f95514a1d 100644 --- a/src/Hook/useMap.example.md +++ b/src/Hook/useMap.example.md @@ -3,7 +3,7 @@ with [react 16.3](https://reactjs.org/docs/context.html). ```jsx import LayerTree from '@terrestris/react-geo/dist/LayerTree/LayerTree'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import { useMap } from '@terrestris/react-util/dist/Hooks/useMap/useMap'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/LayerSwitcher/LayerSwitcher.example.md b/src/LayerSwitcher/LayerSwitcher.example.md index e22a7e6f41..0c19c18e28 100644 --- a/src/LayerSwitcher/LayerSwitcher.example.md +++ b/src/LayerSwitcher/LayerSwitcher.example.md @@ -4,7 +4,7 @@ The passed layers are handled like only one of it can be visible. ```jsx import LayerSwitcher from '@terrestris/react-geo/dist/LayerSwitcher/LayerSwitcher'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; diff --git a/src/LayerSwitcher/LayerSwitcher.tsx b/src/LayerSwitcher/LayerSwitcher.tsx index 4e4025fbc0..0030977c2a 100644 --- a/src/LayerSwitcher/LayerSwitcher.tsx +++ b/src/LayerSwitcher/LayerSwitcher.tsx @@ -1,6 +1,5 @@ import './LayerSwitcher.less'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; import OlLayerBase from 'ol/layer/Base'; import OlLayerGroup from 'ol/layer/Group'; import OlLayerTile from 'ol/layer/Tile'; @@ -9,6 +8,7 @@ import OlTileSource from 'ol/source/Tile'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { CSS_PREFIX } from '../constants'; +import MapComponent from '../Map/MapComponent/MapComponent'; /** * @export diff --git a/src/LayerTree/LayerTree.example.md b/src/LayerTree/LayerTree.example.md index 98d814c582..415a0afdfb 100644 --- a/src/LayerTree/LayerTree.example.md +++ b/src/LayerTree/LayerTree.example.md @@ -2,7 +2,7 @@ This example demonstrates the LayerTree. ```jsx import LayerTree from '@terrestris/react-geo/dist/LayerTree/LayerTree'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; import OlLayerGroup from 'ol/layer/Group'; import OlLayerTile from 'ol/layer/Tile'; diff --git a/src/Legend/Legend.example.md b/src/Legend/Legend.example.md index a1e6f240ab..baafd2ce6a 100644 --- a/src/Legend/Legend.example.md +++ b/src/Legend/Legend.example.md @@ -2,7 +2,7 @@ This example demonstrates the Legend. ```jsx import Legend from '@terrestris/react-geo/dist/Legend/Legend'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; import { diff --git a/src/Map/FloatingMapLogo/FloatingMapLogo.example.md b/src/Map/FloatingMapLogo/FloatingMapLogo.example.md index 1c4892019d..8343c4afd2 100644 --- a/src/Map/FloatingMapLogo/FloatingMapLogo.example.md +++ b/src/Map/FloatingMapLogo/FloatingMapLogo.example.md @@ -1,8 +1,8 @@ This is a example containing a map component and a floating map logo ```jsx -import FloatingMapLogo from '@terrestris/react-util/dist/Components/FloatingMapLogo/FloatingMapLogo'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; +import FloatingMapLogo from '@terrestris/react-geo/dist/Map/FloatingMapLogo/FloatingMapLogo'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; import { diff --git a/src/Map/FloatingMapLogo/FloatingMapLogo.less b/src/Map/FloatingMapLogo/FloatingMapLogo.less new file mode 100644 index 0000000000..e37e8c1a81 --- /dev/null +++ b/src/Map/FloatingMapLogo/FloatingMapLogo.less @@ -0,0 +1,8 @@ +.react-geo-floatingmaplogo { + position: absolute; + left: 5px; + bottom: 5px; + background-color: fade(white, 50%); + border-radius: 5px; + z-index: 10; +} diff --git a/src/Map/FloatingMapLogo/FloatingMapLogo.spec.tsx b/src/Map/FloatingMapLogo/FloatingMapLogo.spec.tsx new file mode 100644 index 0000000000..91a0da5498 --- /dev/null +++ b/src/Map/FloatingMapLogo/FloatingMapLogo.spec.tsx @@ -0,0 +1,30 @@ +import { + render, + screen +} from '@testing-library/react'; +import React from 'react'; + +import testLogo from '../../../assets/user.png'; +import FloatingMapLogo from './FloatingMapLogo'; + +describe('', () => { + it('can be rendered', () => { + const { container } = render( + + ); + expect(container).toBeVisible(); + }); + + it('contains img element with predefined class', () => { + render( + + ); + + const imgEl = screen.getByRole('img'); + expect(imgEl).toHaveClass('react-geo-floatingmaplogo'); + }); +}); diff --git a/src/Map/FloatingMapLogo/FloatingMapLogo.tsx b/src/Map/FloatingMapLogo/FloatingMapLogo.tsx index ff7bd09c0c..2b2e605e4f 100644 --- a/src/Map/FloatingMapLogo/FloatingMapLogo.tsx +++ b/src/Map/FloatingMapLogo/FloatingMapLogo.tsx @@ -1 +1,62 @@ -// placeholder +import './FloatingMapLogo.less'; + +import _cloneDeep from 'lodash/cloneDeep'; +import * as React from 'react'; + +import { CSS_PREFIX } from '../../constants'; + +export type FloatingMapLogoProps = Exclude, 'src' | 'height'> & { + /** + * Whether the map logo is absolutely postioned or not. Default is false. + */ + absolutelyPositioned?: boolean; + + /** + * The imageSrc. + */ + imageSrc: string; + + /** + * The image height + */ + imageHeight?: string; +}; + +export const FloatingMapLogo: React.FC = ({ + absolutelyPositioned = false, + imageSrc, + className, + imageHeight, + style, + ...passThroughProps +}): JSX.Element => { + + const defaultClassName = `${CSS_PREFIX}floatingmaplogo`; + + const finalClassName = className + ? `${className} ${defaultClassName}` + : defaultClassName; + + let imgStyle = style ? _cloneDeep(style) : {}; + + if (absolutelyPositioned) { + imgStyle = { + ...imgStyle, + ...{ + position: 'absolute' + } + }; + } + + return ( + + ); +}; + +export default FloatingMapLogo; diff --git a/src/Map/MapComponent/MapComponent.example.md b/src/Map/MapComponent/MapComponent.example.md index 15da009408..d6bfd882ab 100644 --- a/src/Map/MapComponent/MapComponent.example.md +++ b/src/Map/MapComponent/MapComponent.example.md @@ -1,48 +1,39 @@ -This example shows the usage of the MapComponent in combination with the MapContext.Provider. +This example shows the usage of the MapComponent. ```jsx -import NominatimSearch from '@terrestris/react-geo/dist/Field/NominatimSearch/NominatimSearch'; -import MapComponent from '@terrestris/react-util/dist/Components/MapComponent/MapComponent'; -import MapContext from '@terrestris/react-util/dist/Context/MapContext/MapContext'; +import MapComponent from '@terrestris/react-geo/dist/Map/MapComponent/MapComponent'; import OlLayerTile from 'ol/layer/Tile'; import OlMap from 'ol/Map'; +import { + fromLonLat +} from 'ol/proj'; import OlSourceOsm from 'ol/source/OSM'; import OlView from 'ol/View'; -import * as React from 'react'; +import React from 'react'; const MapComponentExample = () => { - - const layer = new OlLayerTile({ - source: new OlSourceOsm() - }); - - const mapId = `map-${Math.random()}`; - const map = new OlMap({ - target: mapId, view: new OlView({ - center: [ - 135.1691495, - 34.6565482 - ], - projection: 'EPSG:4326', - zoom: 16, + center: fromLonLat([ + 7.1219992, + 50.729458 + ]), + zoom: 11 }), - layers: [layer] + layers: [ + new OlLayerTile({ + source: new OlSourceOsm() + }) + ] }); return ( - - NominatimSearch: - - - + ); } diff --git a/src/Map/MapComponent/MapComponent.spec.tsx b/src/Map/MapComponent/MapComponent.spec.tsx new file mode 100644 index 0000000000..65ac207a29 --- /dev/null +++ b/src/Map/MapComponent/MapComponent.spec.tsx @@ -0,0 +1,29 @@ +import { + render +} from '@testing-library/react'; +import { Map } from 'ol'; +import React from 'react'; + +import TestUtil from '../../Util/TestUtil'; +import MapComponent from './MapComponent'; + +describe('', () => { + let map: Map; + + it('is defined', () => { + expect(MapComponent).not.toBeUndefined(); + }); + + beforeEach(() => { + map = TestUtil.createMap(); + }); + + it('can be rendered', () => { + const { container } = render( + + ); + expect(container).toBeVisible(); + }); +}); diff --git a/src/Map/MapComponent/MapComponent.tsx b/src/Map/MapComponent/MapComponent.tsx index ff7bd09c0c..7f9bfbd201 100644 --- a/src/Map/MapComponent/MapComponent.tsx +++ b/src/Map/MapComponent/MapComponent.tsx @@ -1 +1,43 @@ -// placeholder +import OlMap from 'ol/Map'; +import React, { + useCallback +} from 'react'; + +export type MapComponentProps = React.ComponentProps<'div'> & { + map: OlMap; + mapDivId?: string; +}; + +export const MapComponent: React.FC = ({ + map, + mapDivId = 'map', + ...passThroughProps +}): JSX.Element => { + + const refCallback = useCallback((ref: HTMLDivElement) => { + if (!map) { + return; + } + if (ref === null) { + map.setTarget(undefined); + } else { + map.setTarget(ref); + } + }, [map]); + + if (!map) { + return <>; + } + + return ( +