From baaf532a58c8ea9d5c39a262ed850d6dbbe1634e Mon Sep 17 00:00:00 2001 From: Junqiu Lei Date: Wed, 19 Oct 2022 00:29:40 -0700 Subject: [PATCH 1/2] add layers functions to common place and add zoom bar Signed-off-by: Junqiu Lei --- maps_dashboards/package.json | 4 +- .../add_layer_panel/add_layer_panel.tsx | 56 +++++-------- .../layer_config/layer_config_panel.tsx | 1 - .../layer_control_panel.tsx | 72 ++++------------ .../map_container/map_container.scss | 7 ++ .../map_container/map_container.tsx | 32 ++++--- maps_dashboards/public/model/ILayerConfig.ts | 4 +- .../public/model/OSMLayerFunctions.ts | 83 +++++++++++++++++++ .../public/model/layersFunctions.ts | 11 +++ maps_dashboards/yarn.lock | 10 +++ 10 files changed, 172 insertions(+), 108 deletions(-) create mode 100644 maps_dashboards/public/model/OSMLayerFunctions.ts create mode 100644 maps_dashboards/public/model/layersFunctions.ts diff --git a/maps_dashboards/package.json b/maps_dashboards/package.json index 44692ffa..8b56ebe9 100644 --- a/maps_dashboards/package.json +++ b/maps_dashboards/package.json @@ -8,6 +8,8 @@ "osd": "node ../../scripts/osd" }, "dependencies": { - "maplibre-gl": "^2.4.0" + "maplibre-gl": "^2.4.0", + "uuid": "3.3.2", + "prettier": "^2.1.1" } } diff --git a/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx b/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx index 45fa843f..e4e08f09 100644 --- a/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx +++ b/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { Fragment, useState } from 'react'; +import React, { useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -11,15 +11,15 @@ import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle, - EuiSpacer, - EuiTabbedContent, + EuiHorizontalRule, EuiTitle, EuiButton, EuiIcon, EuiKeyPadMenuItem, } from '@elastic/eui'; import './add_layer_panel.scss'; -import { DASHBOARDS_MAPS_LAYER_TYPE } from '../../../common'; +import { v4 as uuidv4 } from 'uuid'; +import { DASHBOARDS_MAPS_LAYER_TYPE, LAYER_VISIBILITY } from '../../../common'; interface Props { setIsLayerConfigVisible: Function; @@ -31,7 +31,17 @@ export const AddLayerPanel = ({ setIsLayerConfigVisible, setSelectedLayerConfig const [isAddNewLayerModalVisible, setIsAddNewLayerModalVisible] = useState(false); function onClickAddNewLayer(layerItem: string) { - // Will add new layer logic + if (layerItem === DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP) { + setSelectedLayerConfig({ + iconType: 'visMapRegion', + name: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, + type: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, + id: uuidv4(), + zoomRange: [0, 22], + opacity: 1, + visibility: LAYER_VISIBILITY.VISIBLE, + }); + } setIsAddNewLayerModalVisible(false); setIsLayerConfigVisible(true); } @@ -56,31 +66,6 @@ export const AddLayerPanel = ({ setIsLayerConfigVisible, setSelectedLayerConfig const closeModal = () => setIsAddNewLayerModalVisible(false); const showModal = () => setIsAddNewLayerModalVisible(true); - const tabs = [ - { - id: 'select-layer-id', - name: 'Select layer', - content: ( - - - {availableLayers} - - ), - }, - { - id: 'import-id', - name: 'Import', - content: ( - - - -

Import GeoJSON or JSON

-
-
- ), - }, - ]; - return (
@@ -96,12 +81,11 @@ export const AddLayerPanel = ({ setIsLayerConfigVisible, setSelectedLayerConfig - + + +

Reference layer

+
+ {availableLayers}
)} diff --git a/maps_dashboards/public/components/layer_config/layer_config_panel.tsx b/maps_dashboards/public/components/layer_config/layer_config_panel.tsx index f1802d4b..02de274e 100644 --- a/maps_dashboards/public/components/layer_config/layer_config_panel.tsx +++ b/maps_dashboards/public/components/layer_config/layer_config_panel.tsx @@ -39,7 +39,6 @@ export const LayerConfigPanel = ({ }; const onUpdate = () => { updateLayer(); - selectedLayerConfig.update?.(); onClose(); }; diff --git a/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx b/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx index 3f1c71d9..f11c925b 100644 --- a/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx +++ b/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx @@ -17,10 +17,12 @@ import { import { I18nProvider } from '@osd/i18n/react'; import { Map as Maplibre } from 'maplibre-gl'; import './layer_control_panel.scss'; +import { v4 as uuidv4 } from 'uuid'; import { AddLayerPanel } from '../add_layer_panel'; import { LayerConfigPanel } from '../layer_config'; import { ILayerConfig } from '../../model/ILayerConfig'; -import { DASHBOARDS_MAPS_LAYER_TYPE, MAP_VECTOR_TILE_URL, LAYER_VISIBILITY } from '../../../common'; +import { DASHBOARDS_MAPS_LAYER_TYPE, LAYER_VISIBILITY } from '../../../common'; +import { layersFunctionMap } from '../../model/layersFunctions'; interface MaplibreRef { current: Maplibre | null; @@ -47,65 +49,22 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { const [layers, setLayers] = useState([ { iconType: 'visMapRegion', - id: 'example_id_1', + id: 'initial' + uuidv4(), type: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, - name: 'Base Map Layer', - zoomRange: [0, 12], + name: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, + zoomRange: [0, 22], opacity: 1, visibility: LAYER_VISIBILITY.VISIBLE, - update() { - const maplibreInstance = maplibreRef.current; - if (maplibreInstance) { - const baseMapJson = maplibreInstance.getStyle().layers; - if (baseMapJson) { - baseMapJson.forEach((mbLayer) => { - maplibreInstance.setLayerZoomRange(mbLayer.id, this.zoomRange[0], this.zoomRange[1]); - // it will catch error when update opacity in symbol type layer, need figure out later - if (mbLayer.type === 'symbol') { - return; - } - maplibreInstance.setPaintProperty( - mbLayer.id, - `${mbLayer.type}-opacity`, - this.opacity - ); - maplibreInstance.setLayoutProperty(mbLayer.id, 'visibility', this.visibility); - }); - } else { - maplibreInstance.setStyle(MAP_VECTOR_TILE_URL); - } - } - }, - hide() { - const maplibreInstance = maplibreRef.current; - if (maplibreInstance) { - const baseMapJson = maplibreInstance.getStyle().layers; - if (baseMapJson) { - baseMapJson.forEach((mbLayer) => { - maplibreInstance.setLayoutProperty(mbLayer.id, 'visibility', this.visibility); - }); - } - } - }, - remove() { - const maplibreInstance = maplibreRef.current; - if (maplibreInstance) { - const baseMapJson = maplibreInstance.getStyle().layers; - if (baseMapJson) { - baseMapJson.forEach((mbLayer) => { - maplibreInstance.removeLayer(mbLayer.id); - }); - } - } - }, - }, + } ]); useEffect(() => { - layers.forEach((layer) => { - layer.update?.(); - }); - }, [layers]); + maplibreRef.current.on('style.load', function () { + layers.forEach((layer) => { + layersFunctionMap[layer.type]?.update(maplibreRef, layer); + }); + }) + }, []); const updateLayers = () => { const layersClone = [...layers]; @@ -119,6 +78,7 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { layersClone.push(selectedLayerConfig); } setLayers(layersClone); + layersFunctionMap[selectedLayerConfig.type]?.update(maplibreRef, selectedLayerConfig); }; const removeLayer = (index: number) => { @@ -196,7 +156,7 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { } else { layer.visibility = LAYER_VISIBILITY.VISIBLE; } - layer.hide(index); + layersFunctionMap[layer.type]?.hide(maplibreRef, layer); }} aria-label="Hide or show layer" color="text" @@ -208,7 +168,7 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { size="s" iconType="trash" onClick={() => { - layer.remove(index); + layersFunctionMap[layer.type]?.remove(maplibreRef, layer); removeLayer(index); }} aria-label="Delete layer" diff --git a/maps_dashboards/public/components/map_container/map_container.scss b/maps_dashboards/public/components/map_container/map_container.scss index e73cad5b..be555172 100644 --- a/maps_dashboards/public/components/map_container/map_container.scss +++ b/maps_dashboards/public/components/map_container/map_container.scss @@ -22,3 +22,10 @@ left: $euiSizeS; top: $euiSizeS; } + +.zoombar { + z-index: 1; + position: absolute; + bottom: $euiSizeM; + right: $euiSizeS; +} diff --git a/maps_dashboards/public/components/map_container/map_container.tsx b/maps_dashboards/public/components/map_container/map_container.tsx index 8d53d3e7..12bddbe6 100644 --- a/maps_dashboards/public/components/map_container/map_container.tsx +++ b/maps_dashboards/public/components/map_container/map_container.tsx @@ -3,7 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { + EuiPanel, +} from '@elastic/eui'; import { Map as Maplibre, NavigationControl } from 'maplibre-gl'; import { LayerControlPanel } from '../layer_control_panel'; import './map_container.scss'; @@ -12,27 +15,34 @@ import { MAP_VECTOR_TILE_URL, MAP_INITIAL_STATE } from '../../../common/index'; export const MapContainer = () => { const maplibreRef = useRef(null); const mapContainer = useRef(null); + const [mounted, setMounted] = useState(false); + const [zoom, setZoom] = useState(MAP_INITIAL_STATE.zoom); useEffect(() => { - const mapStyle = MAP_VECTOR_TILE_URL; - const initialState = MAP_INITIAL_STATE; - const maplibre = new Maplibre({ - // @ts-ignore + style: MAP_VECTOR_TILE_URL, container: mapContainer.current, - center: [initialState.lng, initialState.lat], - zoom: initialState.zoom, + center: [MAP_INITIAL_STATE.lng, MAP_INITIAL_STATE.lat], + zoom: zoom }); - - maplibre.setStyle(mapStyle); - maplibreRef.current = maplibre; maplibre.addControl(new NavigationControl({ showCompass: false }), 'top-right'); + maplibreRef.current = maplibre + setMounted(true); }, []); + useEffect(() => { + maplibreRef.current.on('move', () => { + setZoom(maplibreRef.current.getZoom().toFixed(2)); + }); + }, [zoom]); + return (
+ +

Zoom: {zoom}

+
- + {mounted && }
diff --git a/maps_dashboards/public/model/ILayerConfig.ts b/maps_dashboards/public/model/ILayerConfig.ts index f9c54749..d83a4824 100644 --- a/maps_dashboards/public/model/ILayerConfig.ts +++ b/maps_dashboards/public/model/ILayerConfig.ts @@ -4,6 +4,7 @@ */ export interface ILayerConfig { + isNewLayer: boolean; name: string; id: string; type: string; @@ -11,7 +12,4 @@ export interface ILayerConfig { zoomRange: number[]; opacity: number; visibility: string; - update: any; - remove: any; - hide: any; } diff --git a/maps_dashboards/public/model/OSMLayerFunctions.ts b/maps_dashboards/public/model/OSMLayerFunctions.ts new file mode 100644 index 00000000..14d82531 --- /dev/null +++ b/maps_dashboards/public/model/OSMLayerFunctions.ts @@ -0,0 +1,83 @@ +import { Map as Maplibre } from 'maplibre-gl'; +import { ILayerConfig } from './ILayerConfig'; + +interface MaplibreRef { + current: Maplibre | null; +} + +// Functions for OpenSearch maps vector tile layer +export const OSMLayerFunctions = { + initial: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { + const maplibreInstance = maplibreRef.current + if (maplibreInstance) { + const mbLayerJson = maplibreInstance.getStyle().layers; + mbLayerJson.map((mbLayer: { id: string }) => { + if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + maplibreInstance.setLayerZoomRange( + mbLayer.id, + layerConfig.zoomRange[0], + layerConfig.zoomRange[1] + ); + // TODO: figure out error reason + if (mbLayer.type === 'symbol') { + return; + } + maplibreInstance.setPaintProperty( + mbLayer.id, + `${mbLayer.type}-opacity`, + layerConfig.opacity + ); + } + }); + } + }, + update: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { + const maplibreInstance = maplibreRef.current; + if (maplibreInstance) { + const mbLayerJson = maplibreInstance.getStyle().layers; + mbLayerJson.forEach((mbLayer: { id: any; type: string }) => { + if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + maplibreInstance.setLayerZoomRange( + mbLayer.id, + layerConfig.zoomRange[0], + layerConfig.zoomRange[1] + ); + if (mbLayer.type === 'symbol') { + return; + } + maplibreInstance.setPaintProperty( + mbLayer.id, + `${mbLayer.type}-opacity`, + layerConfig.opacity + ); + } + }); + } + }, + remove: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { + const maplibreInstance = maplibreRef.current; + if (maplibreInstance) { + const mbLayerJson = maplibreInstance.getStyle().layers; + if (mbLayerJson) { + mbLayerJson.forEach((mbLayer: { id: any }) => { + if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + maplibreInstance.removeLayer(mbLayer.id); + } + }); + } + } + }, + hide: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { + const maplibreInstance = maplibreRef.current; + if (maplibreInstance) { + const mbLayerJson = maplibreInstance.getStyle().layers; + if (mbLayerJson) { + mbLayerJson.forEach((mbLayer: { id: any }) => { + if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + maplibreInstance.setLayoutProperty(mbLayer.id, 'visibility', layerConfig.visibility); + } + }); + } + } + }, +}; diff --git a/maps_dashboards/public/model/layersFunctions.ts b/maps_dashboards/public/model/layersFunctions.ts new file mode 100644 index 00000000..eee50a51 --- /dev/null +++ b/maps_dashboards/public/model/layersFunctions.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DASHBOARDS_MAPS_LAYER_TYPE } from '../../common'; +import { OSMLayerFunctions } from './OSMLayerFunctions'; + +export const layersFunctionMap = { + [DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP]: OSMLayerFunctions, +}; diff --git a/maps_dashboards/yarn.lock b/maps_dashboards/yarn.lock index 4f6e9646..818b5a9f 100644 --- a/maps_dashboards/yarn.lock +++ b/maps_dashboards/yarn.lock @@ -183,6 +183,11 @@ potpack@^1.0.2: resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14" integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ== +prettier@^2.1.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + protocol-buffers-schema@^3.3.1: version "3.6.0" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" @@ -212,6 +217,11 @@ tinyqueue@^2.0.3: resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA== +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + vt-pbf@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac" From bd1fcbc3d95fae61bb69f912fe044aba8b0fccc9 Mon Sep 17 00:00:00 2001 From: Junqiu Lei Date: Fri, 21 Oct 2022 01:25:47 -0700 Subject: [PATCH 2/2] update functions Signed-off-by: Junqiu Lei --- maps_dashboards/common/index.ts | 4 +- .../add_layer_panel/add_layer_panel.tsx | 1 - .../layer_config/layer_config_panel.tsx | 1 - .../layer_control_panel.tsx | 55 ++++++++++-------- .../map_container/map_container.tsx | 39 +++++++++---- maps_dashboards/public/model/ILayerConfig.ts | 2 +- .../public/model/OSMLayerFunctions.ts | 58 ++++++++++++++++--- 7 files changed, 113 insertions(+), 47 deletions(-) diff --git a/maps_dashboards/common/index.ts b/maps_dashboards/common/index.ts index e131abe8..a45056be 100644 --- a/maps_dashboards/common/index.ts +++ b/maps_dashboards/common/index.ts @@ -6,7 +6,9 @@ export const PLUGIN_ID = 'maps-dashboards'; export const PLUGIN_NAME = 'Maps'; -export const MAP_VECTOR_TILE_URL = 'https://tiles.maps.opensearch.org/styles/basic.json'; +export const MAP_VECTOR_TILE_BASIC_STYLE = 'https://tiles.maps.opensearch.org/styles/basic.json'; +export const MAP_GLYPHS = 'https://tiles.maps.opensearch.org/fonts/{fontstack}/{range}.pbf'; +export const MAP_VECTOR_TILE_DATA_SOURCE = 'https://tiles.maps.opensearch.org/data/v1.json'; // Starting position [lng, lat] and zoom export const MAP_INITIAL_STATE = { diff --git a/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx b/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx index e4e08f09..6f88f464 100644 --- a/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx +++ b/maps_dashboards/public/components/add_layer_panel/add_layer_panel.tsx @@ -24,7 +24,6 @@ import { DASHBOARDS_MAPS_LAYER_TYPE, LAYER_VISIBILITY } from '../../../common'; interface Props { setIsLayerConfigVisible: Function; setSelectedLayerConfig: Function; - addNewLayerToList: Function; } export const AddLayerPanel = ({ setIsLayerConfigVisible, setSelectedLayerConfig }: Props) => { diff --git a/maps_dashboards/public/components/layer_config/layer_config_panel.tsx b/maps_dashboards/public/components/layer_config/layer_config_panel.tsx index 02de274e..e879330a 100644 --- a/maps_dashboards/public/components/layer_config/layer_config_panel.tsx +++ b/maps_dashboards/public/components/layer_config/layer_config_panel.tsx @@ -23,7 +23,6 @@ interface Props { setIsLayerConfigVisible: Function; selectedLayerConfig: ILayerConfig; setSelectedLayerConfig: Function; - addNewLayerFunction: Function; updateLayer: Function; } diff --git a/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx b/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx index f11c925b..f690c2b7 100644 --- a/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx +++ b/maps_dashboards/public/components/layer_control_panel/layer_control_panel.tsx @@ -21,7 +21,11 @@ import { v4 as uuidv4 } from 'uuid'; import { AddLayerPanel } from '../add_layer_panel'; import { LayerConfigPanel } from '../layer_config'; import { ILayerConfig } from '../../model/ILayerConfig'; -import { DASHBOARDS_MAPS_LAYER_TYPE, LAYER_VISIBILITY } from '../../../common'; +import { + DASHBOARDS_MAPS_LAYER_TYPE, + LAYER_VISIBILITY, + MAP_VECTOR_TILE_BASIC_STYLE, +} from '../../../common'; import { layersFunctionMap } from '../../model/layersFunctions'; interface MaplibreRef { @@ -46,39 +50,45 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { visibility: '', }); - const [layers, setLayers] = useState([ - { - iconType: 'visMapRegion', - id: 'initial' + uuidv4(), - type: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, - name: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, - zoomRange: [0, 22], - opacity: 1, - visibility: LAYER_VISIBILITY.VISIBLE, - } - ]); + const initialLoadLayer: ILayerConfig = { + iconType: 'visMapRegion', + id: uuidv4(), + type: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, + name: DASHBOARDS_MAPS_LAYER_TYPE.OPENSEARCH_MAP, + zoomRange: [0, 22], + opacity: 1, + visibility: LAYER_VISIBILITY.VISIBLE, + layerSpec: { + OSMUrl: MAP_VECTOR_TILE_BASIC_STYLE, + }, + }; + + const [layers, setLayers] = useState([initialLoadLayer]); useEffect(() => { - maplibreRef.current.on('style.load', function () { + maplibreRef.current?.on('load', function () { layers.forEach((layer) => { - layersFunctionMap[layer.type]?.update(maplibreRef, layer); + layersFunctionMap[layer.type]?.initial(maplibreRef, layer); }); - }) + }); }, []); - const updateLayers = () => { + const updateLayer = () => { const layersClone = [...layers]; const index = layersClone.findIndex((layer) => layer.id === selectedLayerConfig.id); - if (index > -1) { + if (index <= -1) { + layersClone.push(selectedLayerConfig); + layersFunctionMap[selectedLayerConfig.type]?.addNewLayer(maplibreRef, selectedLayerConfig); + } else { layersClone[index] = { ...layersClone[index], ...selectedLayerConfig, }; - } else { - layersClone.push(selectedLayerConfig); } setLayers(layersClone); - layersFunctionMap[selectedLayerConfig.type]?.update(maplibreRef, selectedLayerConfig); + setTimeout(function () { + layersFunctionMap[selectedLayerConfig.type]?.update(maplibreRef, selectedLayerConfig); + }, 50); }; const removeLayer = (index: number) => { @@ -148,7 +158,7 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { { if (layer.visibility === LAYER_VISIBILITY.VISIBLE) { @@ -186,14 +196,13 @@ const LayerControlPanel = ({ maplibreRef }: Props) => { )} diff --git a/maps_dashboards/public/components/map_container/map_container.tsx b/maps_dashboards/public/components/map_container/map_container.tsx index 12bddbe6..8615a91d 100644 --- a/maps_dashboards/public/components/map_container/map_container.tsx +++ b/maps_dashboards/public/components/map_container/map_container.tsx @@ -4,13 +4,11 @@ */ import React, { useEffect, useRef, useState } from 'react'; -import { - EuiPanel, -} from '@elastic/eui'; +import { EuiPanel } from '@elastic/eui'; import { Map as Maplibre, NavigationControl } from 'maplibre-gl'; import { LayerControlPanel } from '../layer_control_panel'; import './map_container.scss'; -import { MAP_VECTOR_TILE_URL, MAP_INITIAL_STATE } from '../../../common/index'; +import { MAP_INITIAL_STATE, MAP_GLYPHS, MAP_VECTOR_TILE_DATA_SOURCE } from '../../../common'; export const MapContainer = () => { const maplibreRef = useRef(null); @@ -19,23 +17,42 @@ export const MapContainer = () => { const [zoom, setZoom] = useState(MAP_INITIAL_STATE.zoom); useEffect(() => { - const maplibre = new Maplibre({ - style: MAP_VECTOR_TILE_URL, + const mbStyle = { + version: 8 as 8, + sources: {}, + layers: [], + glyphs: MAP_GLYPHS, + }; + + maplibreRef.current = new Maplibre({ + // @ts-ignore container: mapContainer.current, center: [MAP_INITIAL_STATE.lng, MAP_INITIAL_STATE.lat], - zoom: zoom + zoom, + style: mbStyle, + }); + + maplibreRef.current.addControl(new NavigationControl({ showCompass: false }), 'top-right'); + maplibreRef.current.on('style.load', function () { + // @ts-ignore + maplibreRef.current.addSource('openmaptiles', { + type: 'vector', + url: MAP_VECTOR_TILE_DATA_SOURCE, + }); + setMounted(true); }); - maplibre.addControl(new NavigationControl({ showCompass: false }), 'top-right'); - maplibreRef.current = maplibre - setMounted(true); }, []); useEffect(() => { + // @ts-ignore maplibreRef.current.on('move', () => { - setZoom(maplibreRef.current.getZoom().toFixed(2)); + // @ts-ignore + return setZoom(maplibreRef.current.getZoom().toFixed(2)); }); }, [zoom]); + useEffect(() => {}, []); + return (
diff --git a/maps_dashboards/public/model/ILayerConfig.ts b/maps_dashboards/public/model/ILayerConfig.ts index d83a4824..9a6dcd4e 100644 --- a/maps_dashboards/public/model/ILayerConfig.ts +++ b/maps_dashboards/public/model/ILayerConfig.ts @@ -4,7 +4,6 @@ */ export interface ILayerConfig { - isNewLayer: boolean; name: string; id: string; type: string; @@ -12,4 +11,5 @@ export interface ILayerConfig { zoomRange: number[]; opacity: number; visibility: string; + layerSpec?: any; } diff --git a/maps_dashboards/public/model/OSMLayerFunctions.ts b/maps_dashboards/public/model/OSMLayerFunctions.ts index 14d82531..7cb565da 100644 --- a/maps_dashboards/public/model/OSMLayerFunctions.ts +++ b/maps_dashboards/public/model/OSMLayerFunctions.ts @@ -1,5 +1,6 @@ -import { Map as Maplibre } from 'maplibre-gl'; +import { Map as Maplibre, LayerSpecification } from 'maplibre-gl'; import { ILayerConfig } from './ILayerConfig'; +import { MAP_VECTOR_TILE_BASIC_STYLE } from '../../common'; interface MaplibreRef { current: Maplibre | null; @@ -8,11 +9,29 @@ interface MaplibreRef { // Functions for OpenSearch maps vector tile layer export const OSMLayerFunctions = { initial: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { - const maplibreInstance = maplibreRef.current + const maplibreInstance = maplibreRef.current; if (maplibreInstance) { - const mbLayerJson = maplibreInstance.getStyle().layers; - mbLayerJson.map((mbLayer: { id: string }) => { - if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + const renderStyleData = async () => { + try { + const response = await fetch(MAP_VECTOR_TILE_BASIC_STYLE); + const json = await response.json(); + const styleLayers: LayerSpecification[] = await json.layers; + styleLayers.forEach((styleLayer) => { + styleLayer.id = styleLayer.id + '_' + layerConfig.id; + // @ts-ignore + maplibreRef.current.addLayer(styleLayer); + }); + } catch (error) { + console.log('error', error); + } + }; + renderStyleData(); + + // @ts-ignore + setTimeout(function () { + const mbLayerJson: LayerSpecification[] = maplibreRef.current.getStyle().layers; + mbLayerJson.map((mbLayer) => { + if (mbLayer.id.includes(layerConfig.id)) { maplibreInstance.setLayerZoomRange( mbLayer.id, layerConfig.zoomRange[0], @@ -28,7 +47,8 @@ export const OSMLayerFunctions = { layerConfig.opacity ); } - }); + }); + }, 50); } }, update: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { @@ -36,7 +56,7 @@ export const OSMLayerFunctions = { if (maplibreInstance) { const mbLayerJson = maplibreInstance.getStyle().layers; mbLayerJson.forEach((mbLayer: { id: any; type: string }) => { - if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + if (mbLayer.id.includes(layerConfig.id)) { maplibreInstance.setLayerZoomRange( mbLayer.id, layerConfig.zoomRange[0], @@ -54,13 +74,33 @@ export const OSMLayerFunctions = { }); } }, + addNewLayer: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { + const maplibreInstance = maplibreRef.current; + if (maplibreInstance) { + const renderStyleData = async () => { + try { + const response = await fetch(MAP_VECTOR_TILE_BASIC_STYLE); + const json = await response.json(); + const styleLayers: LayerSpecification[] = await json.layers; + styleLayers.forEach((styleLayer) => { + styleLayer.id = styleLayer.id + '_' + layerConfig.id; + // @ts-ignore + maplibreRef.current.addLayer(styleLayer); + }); + } catch (error) { + console.log('error', error); + } + }; + renderStyleData(); + } + }, remove: (maplibreRef: MaplibreRef, layerConfig: ILayerConfig) => { const maplibreInstance = maplibreRef.current; if (maplibreInstance) { const mbLayerJson = maplibreInstance.getStyle().layers; if (mbLayerJson) { mbLayerJson.forEach((mbLayer: { id: any }) => { - if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + if (mbLayer.id.includes(layerConfig.id)) { maplibreInstance.removeLayer(mbLayer.id); } }); @@ -73,7 +113,7 @@ export const OSMLayerFunctions = { const mbLayerJson = maplibreInstance.getStyle().layers; if (mbLayerJson) { mbLayerJson.forEach((mbLayer: { id: any }) => { - if (mbLayer.id.includes(layerConfig.id) || layerConfig.id.includes('initial')) { + if (mbLayer.id.includes(layerConfig.id)) { maplibreInstance.setLayoutProperty(mbLayer.id, 'visibility', layerConfig.visibility); } });