From 90f9c098018f04c74c01ef6539a1199c5deba060 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 21 Nov 2023 18:08:11 +0100 Subject: [PATCH] WIP --- .../src/components/MapPoi/Map.ts | 103 ++++++++++-------- .../src/components/MapPoi/constants.ts | 3 +- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/packages/visualizations/src/components/MapPoi/Map.ts b/packages/visualizations/src/components/MapPoi/Map.ts index f883a575..3b12401b 100644 --- a/packages/visualizations/src/components/MapPoi/Map.ts +++ b/packages/visualizations/src/components/MapPoi/Map.ts @@ -49,8 +49,8 @@ export default class MapPOI { /** Popups configurations. One configuration by layer */ private popupsConfiguration: PopupsConfiguration = {}; - /** An array of GeoJSONFeatures associated with the popup. */ - private popupFeatures: MapGeoJSONFeature[] = []; + /** An active GeoJSONFeature. Its information are displayed within the popup. */ + private activeFeature: MapGeoJSONFeature | null = null; /** An array of functions to be executed when the map is ready. */ private queuedFunctions: Array = []; @@ -118,19 +118,11 @@ export default class MapPOI { private onClick({ point }: MapLayerMouseEvent) { this.queue((map) => { /** - * Get features closed to the click. + * Get features closed to the click area. * We ask for features that are not in base style layers */ const features = map.queryRenderedFeatures(point, { layers: this.layerIds }); - - // Will close the popup - if (this.popupFeatures.length) return; - - // If features from selected layers, update the popup - if (features.length) { - this.popupFeatures = features; - this.setPopup(map); - } + this.updatePopup(map, features); }); } @@ -143,26 +135,39 @@ export default class MapPOI { private bindedResetLeftPaddingPopup = this.resetLeftPaddingPopup.bind(this); - /** Event handler for popup close event. */ - private onPopupClose() { - this.popupFeatures.forEach(({ source, sourceLayer, id }) => { - if (this.sourceIds.includes(source)) { - this.queue((map) => { - map.setFeatureState({ source, sourceLayer, id }, { 'popup-feature': false }); - }); - } - }); - this.popupFeatures = []; - } - - private bindedOnPopupClose = this.onPopupClose.bind(this); - /** Set the popup content and positioning */ - private setPopup(map: maplibregl.Map) { - if (!this.popupFeatures.length) return; + private updatePopup(map: maplibregl.Map, features: MapGeoJSONFeature[]) { + if(this.activeFeature) { + const { + id, + source, + sourceLayer, + } = this.activeFeature; + map.setFeatureState({ source, sourceLayer, id }, { 'popup-feature': false }); + } + const hasFeatures = !!features.length; // Current rule: use the first feature to build the popup. // TO DO: Create a menu to display a list of feature to choose from. + const isSelectedFeatureSameAsActiveFeature = + hasFeatures && + !!this.activeFeature && + features[0].layer.id === this.activeFeature?.layer.id && + features[0].id === this.activeFeature.id; + + // Close popup if: + // - No features in parameters + // - Selected feature is the same as the active feature: This means that I clicked on the feature for which the popup is open. + if (!hasFeatures || isSelectedFeatureSameAsActiveFeature) { + this.popup.remove(); + return; + } + + + // FIXME: remove eslint comment. + // eslint-disable-next-line prefer-destructuring + this.activeFeature = features[0]; + const { id: featureId, layer: { id: layerId }, @@ -170,31 +175,28 @@ export default class MapPOI { properties, source, sourceLayer, - } = this.popupFeatures[0]; + } = this.activeFeature; if (geometry.type !== 'Point') return; - // Get the popup configuration for a layer - const popupConfiguration = this.popupsConfiguration[layerId]; - /* - * We remove the popup if: - * - no popup configuration for a layer - * - popup's source is no longer used in the map - */ + * We remove the popup if: + * - no popup configuration for a layer + * - popup's source is no longer used in the map + */ + const popupConfiguration = this.popupsConfiguration[layerId]; if (!popupConfiguration || !this.sourceIds.includes(source)) { this.popup.remove(); - this.popupFeatures = []; return; } const { display, getContent, getLoadingContent } = popupConfiguration; - - if (this.popup.isOpen() === false) { - this.popup.setLngLat(geometry.coordinates as LngLatLike).addTo(map); + + if(!this.popup.isOpen()) { + this.popup.addTo(map); } + this.popup.setLngLat(geometry.coordinates as LngLatLike).setHTML(getLoadingContent()); - this.popup.setHTML(getLoadingContent()); getContent(featureId, properties).then((content) => { this.popup.setHTML(content); }); @@ -202,6 +204,12 @@ export default class MapPOI { const classnameModifier = display === 'sidebar' ? 'addClassName' : 'removeClassName'; this.popup[classnameModifier](`${POPUP_OPTIONS.className}--as-sidebar`); + map.setFeatureState({ source, sourceLayer, id: featureId }, { 'popup-feature': true }); + + this.popup.once('close', () => { + this.activeFeature = null; + map.setFeatureState({ source, sourceLayer, id: featureId }, { 'popup-feature': false });}); + if (display === 'sidebar') { map.easeTo({ center: geometry.coordinates as LngLatLike, @@ -209,10 +217,6 @@ export default class MapPOI { }); this.popup.on('close', this.bindedResetLeftPaddingPopup); } - - if (featureId) { - map.setFeatureState({ source, sourceLayer, id: featureId }, { 'popup-feature': true }); - } } initialize( @@ -230,14 +234,13 @@ export default class MapPOI { if (this.map) { // Store base style after the first load this.baseStyle = this.map?.getStyle(); - this.popup.on('close', this.bindedOnPopupClose); this.enqueue(this.map); } }); } destroy() { - this.popupFeatures = []; + this.activeFeature = null; this.popup.remove(); this.queue((map) => map.remove()); this.mapResizeObserver?.disconnect(); @@ -315,7 +318,11 @@ export default class MapPOI { setPopupsConfiguration(config: PopupsConfiguration) { this.popupsConfiguration = config; - this.queue((map) => this.setPopup(map)); + this.queue((map) => { + if (this.activeFeature) { + this.updatePopup(map, [this.activeFeature]); + } + }); } toggleInteractivity( diff --git a/packages/visualizations/src/components/MapPoi/constants.ts b/packages/visualizations/src/components/MapPoi/constants.ts index 5cb80bda..9aab3ce9 100644 --- a/packages/visualizations/src/components/MapPoi/constants.ts +++ b/packages/visualizations/src/components/MapPoi/constants.ts @@ -16,6 +16,7 @@ export const POPUP_WIDTH = 300; export const POPUP_OPTIONS: PopupOptions = { className: 'poi-map__popup', - closeButton: false, + closeButton: true, + closeOnClick: false, maxWidth: `${POPUP_WIDTH}px`, };