Skip to content

Commit

Permalink
fix(POI Map): Switch between tooltips
Browse files Browse the repository at this point in the history
It's no longer necessary to close one tooltip before opening another.
  • Loading branch information
KevinFabre-ods committed Nov 22, 2023
1 parent 064db68 commit 9e3e112
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 45 deletions.
91 changes: 47 additions & 44 deletions packages/visualizations/src/components/MapPoi/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<MapFunction> = [];
Expand Down Expand Up @@ -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);
});
}

Expand All @@ -143,59 +135,64 @@ 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 },
geometry,
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
*/
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.addClassName(`${POPUP_CLASSNAME}--loading`);
this.popup.setHTML(getLoadingContent());
this.popup.setLngLat(geometry.coordinates as LngLatLike).setHTML(getLoadingContent());

getContent(featureId, properties).then((content) => {
this.popup.setHTML(content);
this.popup.removeClassName(`${POPUP_CLASSNAME}--loading`);
Expand All @@ -204,17 +201,20 @@ export default class MapPOI {
const classnameModifier = display === 'sidebar' ? 'addClassName' : 'removeClassName';
this.popup[classnameModifier](`${POPUP_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,
padding: { left: POPUP_WIDTH },
});
this.popup.on('close', this.bindedResetLeftPaddingPopup);
}

if (featureId) {
map.setFeatureState({ source, sourceLayer, id: featureId }, { 'popup-feature': true });
}
}

initialize(
Expand All @@ -232,14 +232,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();
Expand Down Expand Up @@ -317,7 +316,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(
Expand Down
3 changes: 2 additions & 1 deletion packages/visualizations/src/components/MapPoi/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const POPUP_WIDTH = 300;
export const POPUP_CLASSNAME = 'poi-map__popup';

export const POPUP_OPTIONS: PopupOptions = {
className: `${POPUP_CLASSNAME} ${POPUP_CLASSNAME}--loading`,
className: POPUP_CLASSNAME,
closeButton: true,
closeOnClick: false,
};

0 comments on commit 9e3e112

Please sign in to comment.