From 78be00a3add4e8e02c90c7caf83ec6ee70f871e5 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 26 Feb 2024 16:57:01 -0500 Subject: [PATCH] Started... Finished --- .../public/templates/sandbox.html | 14 ++- .../map-event-processor.ts | 9 +- packages/geoview-core/src/app.tsx | 2 +- packages/geoview-core/src/core/app-start.tsx | 8 +- .../geoview-layers/abstract-geoview-layers.ts | 4 +- .../geoview-core/src/geo/map/map-viewer.ts | 99 ++++++++++++++----- 6 files changed, 101 insertions(+), 35 deletions(-) diff --git a/packages/geoview-core/public/templates/sandbox.html b/packages/geoview-core/public/templates/sandbox.html index 758cdef4892..2bd75b87081 100644 --- a/packages/geoview-core/public/templates/sandbox.html +++ b/packages/geoview-core/public/templates/sandbox.html @@ -143,7 +143,7 @@

Sanbox Map

Top
-
+

This map loads it's configurations from the text area.


@@ -194,11 +194,17 @@

Sanbox Map

// add an event listener when a button is clicked createMapButton.addEventListener('click', function (e) { // delete old map - const mapDiv = cgpv.api.maps['sandboxMap'].remove(false); - mapDiv.classList.remove('geoview-map'); + cgpv.api.maps['sandboxMap'].remove(true); + + // create new map in a new dom node + const newDiv = document.createElement('div'); + const a = document.createAttribute("id"); + a.value = "sandboxMap"; + newDiv.setAttributeNode(a); + document.getElementById('mapSection').appendChild(newDiv); // create map - setTimeout(() => cgpv.api.createMapFromConfig('sandboxMap', document.getElementById('configGeoview').value), 1000); + setTimeout(() => cgpv.api.createMapFromConfig('sandboxMap', document.getElementById('configGeoview').value), 300); }); // Editor script section=================================================================================================== diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts index dbcdb0d70dc..c1280c151de 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts @@ -199,8 +199,13 @@ export class MapEventProcessor extends AbstractEventProcessor { // TODO: destroy events on map destruction map.on('change:size', store.getState().mapState.events.onMapChangeSize); map.on('moveend', store.getState().mapState.events.onMapMoveEnd); - map.on('pointermove', store.getState().mapState.events.onMapPointerMove); - map.on('singleclick', store.getState().mapState.events.onMapSingleClick); + + // If not on a static map, wire handlers on pointermove and singleclick + if (store.getState().mapState.interaction !== 'static') { + map.on('pointermove', store.getState().mapState.events.onMapPointerMove); + map.on('singleclick', store.getState().mapState.events.onMapSingleClick); + } + map.getView().on('change:resolution', store.getState().mapState.events.onMapZoomEnd); map.getView().on('change:rotation', store.getState().mapState.events.onMapRotation); diff --git a/packages/geoview-core/src/app.tsx b/packages/geoview-core/src/app.tsx index dcd5f32b082..a6b437495ff 100644 --- a/packages/geoview-core/src/app.tsx +++ b/packages/geoview-core/src/app.tsx @@ -101,7 +101,7 @@ async function renderMap(mapElement: Element): Promise { reactRoot[mapId] = createRoot(mapElement!); addReloadListener(mapId); - // TODO: Refactor #1810 - Activate + // TODO: Refactor #1810 - Activate here or in app-start.tsx? reactRoot[mapId].render(); // reactRoot[mapId].render( // diff --git a/packages/geoview-core/src/core/app-start.tsx b/packages/geoview-core/src/core/app-start.tsx index d1b8550f428..c2cc472bc90 100644 --- a/packages/geoview-core/src/core/app-start.tsx +++ b/packages/geoview-core/src/core/app-start.tsx @@ -77,8 +77,14 @@ function AppStart(props: AppStartProps): JSX.Element { if (!Object.keys(api.maps).includes(mapId)) api.maps[mapId] = new MapViewer(mapFeaturesConfig, i18nInstance); // Start the process of checking for map readiness - api.maps[mapId].mapReady(); + api.maps[mapId].mapReady().then(() => { + // Start the process of checking for layers result set readiness + api.maps[mapId].layerResultSetReady().then(() => { + // Write app-start code logic here to do something when the layers resultset is ready for all layer path + }); + }); + // TODO: Refactor #1810 - Activate here or in app.tsx? return ( diff --git a/packages/geoview-core/src/geo/layer/geoview-layers/abstract-geoview-layers.ts b/packages/geoview-core/src/geo/layer/geoview-layers/abstract-geoview-layers.ts index 983669373bb..3ab7fae7055 100644 --- a/packages/geoview-core/src/geo/layer/geoview-layers/abstract-geoview-layers.ts +++ b/packages/geoview-core/src/geo/layer/geoview-layers/abstract-geoview-layers.ts @@ -961,7 +961,7 @@ export abstract class AbstractGeoViewLayer { * * @param {TypeBaseLayerEntryConfig} layerConfig The layer config to register. */ - registerToLayerSets(layerConfig: TypeBaseLayerEntryConfig) { + registerToLayerSets(layerConfig: TypeBaseLayerEntryConfig): void { const { layerPath } = layerConfig; if (!this.registerToLayerSetListenerFunctions[layerPath]) this.registerToLayerSetListenerFunctions[layerPath] = {}; @@ -1037,7 +1037,7 @@ export abstract class AbstractGeoViewLayer { * * @param {TypeBaseLayerEntryConfig} layerConfig The layer entry to register. */ - unregisterFromLayerSets(layerConfig: TypeBaseLayerEntryConfig) { + unregisterFromLayerSets(layerConfig: TypeBaseLayerEntryConfig): void { const { layerPath } = layerConfig; api.event.emit(LayerSetPayload.createLayerRegistrationPayload(this.mapId, layerPath, 'remove')); diff --git a/packages/geoview-core/src/geo/map/map-viewer.ts b/packages/geoview-core/src/geo/map/map-viewer.ts index a61c0195db8..2faeac4767f 100644 --- a/packages/geoview-core/src/geo/map/map-viewer.ts +++ b/packages/geoview-core/src/geo/map/map-viewer.ts @@ -219,36 +219,85 @@ export class MapViewer { } /** - * Function called when the map has been rendered and ready to be customized + * Function called to monitor when the map is actually ready. + * Important: This function is also responsible for calling the MapEventProcessor.setMapLoaded after 1 second has ellapsed. */ - mapReady(): void { + mapReady(): Promise { // Log Marker Start logger.logMarkerStart(`mapReady-${this.mapId}`); - const layerInterval = setInterval(() => { - // Log - logger.logTraceDetailed('map-viewer.mapReady?', this.mapId); - - if (this.layer?.geoviewLayers) { - const { geoviewLayers } = this.layer; - let allGeoviewLayerReady = - this.mapFeaturesConfig.map.listOfGeoviewLayerConfig?.length === 0 || Object.keys(geoviewLayers).length !== 0; - Object.keys(geoviewLayers).forEach((geoviewLayerId) => { - const layerIsReady = geoviewLayers[geoviewLayerId].allLayerStatusAreGreaterThanOrEqualTo('processed'); - logger.logTraceDetailed('map-viewer.mapReady? geoview layer ready?', geoviewLayerId, layerIsReady); - allGeoviewLayerReady &&= layerIsReady; - }); - if (allGeoviewLayerReady) { - // Log - logger.logInfo('Map is ready', this.mapId); - logger.logMarkerCheck(`mapReady-${this.mapId}`, 'for map to be ready'); - // ! We added processed to layers check so this map loaded event is fired faster - // TODO: solve this without using a timeout... - setTimeout(() => MapEventProcessor.setMapLoaded(this.mapId), 1000); - clearInterval(layerInterval); + return new Promise((resolve) => { + // Start an interval checker + const mapInterval = setInterval(() => { + if (this.layer?.geoviewLayers) { + const { geoviewLayers } = this.layer; + let allGeoviewLayerReady = + this.mapFeaturesConfig.map.listOfGeoviewLayerConfig?.length === 0 || Object.keys(geoviewLayers).length !== 0; + Object.keys(geoviewLayers).forEach((geoviewLayerId) => { + const layerIsReady = geoviewLayers[geoviewLayerId].allLayerStatusAreGreaterThanOrEqualTo('processed'); + if (!layerIsReady) logger.logTraceDetailed('map-viewer.mapReady? geoview layer not ready, waiting...', geoviewLayerId); + allGeoviewLayerReady &&= layerIsReady; + }); + if (allGeoviewLayerReady) { + // Clear interval + clearInterval(mapInterval); + + // Log + logger.logInfo('Map is ready', this.mapId); + logger.logMarkerCheck(`mapReady-${this.mapId}`, 'for map to be ready'); + + // Resolve the promise + resolve(); + + // ! We added processed to layers check so this map loaded event is fired faster + // TODO: solve this without using a timeout... + setTimeout(() => MapEventProcessor.setMapLoaded(this.mapId), 1000); + } } - } - }, 250); + }, 250); + }); + } + + /** + * Function called to monitor when the layers result sets are actually ready + */ + layerResultSetReady(): Promise { + // Start another interval checker + return new Promise((resolve) => { + const layersInterval = setInterval(() => { + if (api.maps[this.mapId].layer) { + // Check if all registered layers have their results set + let allGood = true; + Object.entries(api.maps[this.mapId].layer.registeredLayers).forEach(([layerPath, registeredLayer]) => { + // If not queryable, don't expect a result set + if (!registeredLayer.source?.featureInfo?.queryable) return; + + const { resultSet } = api.getFeatureInfoLayerSet(this.mapId); + const layerResultSetReady = Object.keys(resultSet).includes(layerPath); + if (!layerResultSetReady) { + logger.logTraceDetailed('layer resultset not ready, waiting...', layerPath); + allGood = false; + } + }); + + // If all good + if (allGood) { + // Clear interval + clearInterval(layersInterval); + + // How many layers resultset? + const resultSetCount = Object.keys(api.getFeatureInfoLayerSet(this.mapId).resultSet).length; + + // Log + logger.logInfo(`All (${resultSetCount}) Layers ResultSet are ready`, this.mapId); + logger.logMarkerCheck(`mapReady-${this.mapId}`, `for all (${resultSetCount}) Layers ResultSet to be ready`); + + // Resolve the promise + resolve(); + } + } + }, 250); + }); } /**