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..38498e464e8 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 @@ -173,6 +173,24 @@ export class MapEventProcessor extends AbstractEventProcessor { ); // #endregion FEATURE SELECTION + const unsubOrderedLayerInfo = store.subscribe( + (state) => state.mapState.orderedLayerInfo, + (cur) => { + // Log + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - legendLayers', mapId, cur); + + const visibleLayers = cur + .map((layerInfo) => { + if (layerInfo.visible) return layerInfo.layerPath; + return undefined; + }) + .filter((layerPath) => layerPath); + const prevVisibleLayers = [...store.getState().mapState.visibleLayers]; + if (JSON.stringify(prevVisibleLayers) !== JSON.stringify(visibleLayers)) + store.getState().mapState.actions.setVisibleLayers(visibleLayers as string[]); + } + ); + // Return the array of subscriptions so they can be destroyed later return [ unsubMapHighlightedFeatures, @@ -183,6 +201,7 @@ export class MapEventProcessor extends AbstractEventProcessor { unsubMapSelectedFeatures, unsubMapZoom, unsubMapSingleClick, + unsubOrderedLayerInfo, ]; } diff --git a/packages/geoview-core/src/core/components/data-table/data-panel.tsx b/packages/geoview-core/src/core/components/data-table/data-panel.tsx index 25a50e78398..fa34c0f8f48 100644 --- a/packages/geoview-core/src/core/components/data-table/data-panel.tsx +++ b/packages/geoview-core/src/core/components/data-table/data-panel.tsx @@ -11,7 +11,7 @@ import { useDataTableStoreRowsFiltered, useDataTableStoreSelectedLayerPath, useDetailsStoreLayerDataArray, - useMapOrderedLayerInfo, + useMapVisibleLayers, } from '@/core/stores'; import { ResponsiveGrid, EnlargeButton, CloseButton, LayerList, LayerListEntry, LayerTitle, useFooterPanelHeight } from '../common'; import { logger } from '@/core/utils/logger'; @@ -43,7 +43,7 @@ export function Datapanel() { const isEnlargeDataTable = useDataTableStoreIsEnlargeDataTable(); const mapFiltered = useDataTableStoreMapFilteredRecord(); const rowsFiltered = useDataTableStoreRowsFiltered(); - const orderedLayerInfo = useMapOrderedLayerInfo(); + const visibleLayers = useMapVisibleLayers(); const { setSelectedLayerPath, setIsEnlargeDataTable } = useDataTableStoreActions(); // Custom hook for calculating the height of footer panel @@ -53,17 +53,10 @@ export function Datapanel() { const mappedLayerData = useFeatureFieldInfos(layerData); const orderedLayerData = useMemo(() => { - const visibleLayers = orderedLayerInfo - .map((layerInfo) => { - if (layerInfo.visible) return layerInfo.layerPath; - return undefined; - }) - .filter((layerPath) => layerPath !== undefined); - return visibleLayers .map((layerPath) => mappedLayerData.filter((data) => data.layerPath === layerPath)[0]) .filter((layer) => layer !== undefined); - }, [mappedLayerData, orderedLayerInfo]); + }, [mappedLayerData, visibleLayers]); const handleLayerChange = useCallback( (_layer: LayerListEntry) => { diff --git a/packages/geoview-core/src/core/components/details/details-panel.tsx b/packages/geoview-core/src/core/components/details/details-panel.tsx index 414c0ffc81f..be147d8cef5 100644 --- a/packages/geoview-core/src/core/components/details/details-panel.tsx +++ b/packages/geoview-core/src/core/components/details/details-panel.tsx @@ -14,7 +14,7 @@ import { import { TypeFeatureInfoEntry, TypeLayerData, TypeGeometry, TypeArrayOfFeatureInfoEntries } from '@/api/events/payloads'; import { useMapStoreActions, - useMapOrderedLayerInfo, + useMapVisibleLayers, useDetailsStoreActions, useDetailsStoreCheckedFeatures, useDetailsStoreLayerDataArrayBatch, @@ -48,7 +48,7 @@ export function DetailsPanel({ fullWidth }: DetailsPanelType): JSX.Element { const selectedLayerPath = useDetailsStoreSelectedLayerPath(); const arrayOfLayerDataBatch = useDetailsStoreLayerDataArrayBatch(); const checkedFeatures = useDetailsStoreCheckedFeatures(); - const orderedLayerInfo = useMapOrderedLayerInfo(); + const visibleLayers = useMapVisibleLayers(); const { setSelectedLayerPath, removeCheckedFeature, setLayerDataArrayBatchLayerPathBypass } = useDetailsStoreActions(); const { addSelectedFeature, removeSelectedFeature } = useMapStoreActions(); @@ -122,14 +122,7 @@ export function DetailsPanel({ fullWidth }: DetailsPanelType): JSX.Element { */ const memoLayersList = useMemo(() => { // Log - logger.logTraceUseMemo('DETAILS-PANEL - memoLayersList', orderedLayerInfo, arrayOfLayerDataBatch); - - const visibleLayers = orderedLayerInfo - .map((layerInfo) => { - if (layerInfo.visible) return layerInfo.layerPath; - return undefined; - }) - .filter((layerPath) => layerPath !== undefined); + logger.logTraceUseMemo('DETAILS-PANEL - memoLayersList', visibleLayers, arrayOfLayerDataBatch); if (!visibleLayers.includes(selectedLayerPath)) setSelectedLayerPath(''); @@ -151,7 +144,7 @@ export function DetailsPanel({ fullWidth }: DetailsPanelType): JSX.Element { ); if (!layerListEntries.length) setSelectedLayerPath(''); return layerListEntries; - }, [orderedLayerInfo, arrayOfLayerDataBatch, selectedLayerPath, setSelectedLayerPath, getNumFeaturesLabel]); + }, [arrayOfLayerDataBatch, visibleLayers, selectedLayerPath, setSelectedLayerPath, getNumFeaturesLabel]); /** * Memoizes the selected layer for the LayerList component. diff --git a/packages/geoview-core/src/core/components/legend/legend.tsx b/packages/geoview-core/src/core/components/legend/legend.tsx index 7598d20c142..caa79bc20c2 100644 --- a/packages/geoview-core/src/core/components/legend/legend.tsx +++ b/packages/geoview-core/src/core/components/legend/legend.tsx @@ -2,7 +2,7 @@ import { useTheme } from '@mui/material'; import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, Paper, Typography } from '@/ui'; -import { useLayerLegendLayers, useMapOrderedLayerInfo, useLayerStoreActions } from '@/core/stores/'; +import { useLayerLegendLayers, useLayerStoreActions, useMapVisibleLayers } from '@/core/stores/'; import { logger } from '@/core/utils/logger'; import { getSxClasses } from './legend-styles'; @@ -28,7 +28,7 @@ export function Legend({ fullWidth }: LegendType): JSX.Element { const [formattedLegendLayerList, setFormattedLegendLayersList] = useState([]); // store state - const orderedLayerInfo = useMapOrderedLayerInfo(); + const visibleLayers = useMapVisibleLayers(); const layersList = useLayerLegendLayers(); const { getLayer } = useLayerStoreActions(); @@ -73,14 +73,7 @@ export function Legend({ fullWidth }: LegendType): JSX.Element { useEffect(() => { // Log - logger.logTraceUseEffect('LEGEND - orderedLayerInfo', orderedLayerInfo.length, orderedLayerInfo); - - const visibleLayers = orderedLayerInfo - .map((layerInfo) => { - if (layerInfo.visible) return layerInfo.layerPath; - return undefined; - }) - .filter((layerPath) => layerPath !== undefined); + logger.logTraceUseEffect('LEGEND - orderedLayerInfo', visibleLayers.length, visibleLayers); // Loop on the visible layers to retrieve the valid TypeLegendLayer objects const parentPaths: string[] = []; @@ -100,7 +93,7 @@ export function Legend({ fullWidth }: LegendType): JSX.Element { updateLegendLayerListByWindowSize(layers); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [orderedLayerInfo, layersList]); + }, [visibleLayers, layersList]); useEffect(() => { // Log diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/map-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/map-state.ts index e10d48c5348..27ee10e7809 100644 --- a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/map-state.ts +++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/map-state.ts @@ -65,6 +65,7 @@ export interface IMapState { scale: TypeScaleInfo; selectedFeatures: Array; size: [number, number]; + visibleLayers: string[]; zoom: number; setDefaultConfigValues: (config: TypeMapFeaturesConfig) => void; @@ -109,6 +110,7 @@ export interface IMapState { setProjection: (projectionCode: TypeValidMapProjectionCodes, view: View) => void; setQueryable: (layerPath: string, queryable: boolean) => void; setRotation: (degree: number) => void; + setVisibleLayers: (newVisibleLayers: Array) => void; setZoom: (zoom: number, duration?: number) => void; showClickMarker: (marker: TypeClickMarker) => void; transformPoints: (coords: Coordinate[], outputProjection: number) => Coordinate[]; @@ -151,6 +153,7 @@ export function initializeMapState(set: TypeSetStore, get: TypeGetStore): IMapSt scale: { lineWidth: '', labelGraphic: '', labelNumeric: '' } as TypeScaleInfo, selectedFeatures: [], size: [0, 0] as [number, number], + visibleLayers: [], zoom: 0, // initialize default stores section from config information when store receive configuration file @@ -548,6 +551,14 @@ export function initializeMapState(set: TypeSetStore, get: TypeGetStore): IMapSt // State is set by the map state store event 'onMapRotation' get().mapState.mapElement!.getView().animate({ rotation: degree }); }, + setVisibleLayers: (newVisibleLayers: Array) => { + set({ + mapState: { + ...get().mapState, + visibleLayers: newVisibleLayers, + }, + }); + }, setZoom: (zoom: number, duration?: number) => { // set ol map zoom // State is set by the map state store event 'onMapZoomEnd' @@ -627,6 +638,7 @@ export const useMapRotation = () => useStore(useGeoViewStore(), (state) => state export const useMapSelectedFeatures = () => useStore(useGeoViewStore(), (state) => state.mapState.selectedFeatures); export const useMapScale = () => useStore(useGeoViewStore(), (state) => state.mapState.scale); export const useMapSize = () => useStore(useGeoViewStore(), (state) => state.mapState.size); +export const useMapVisibleLayers = () => useStore(useGeoViewStore(), (state) => state.mapState.visibleLayers); export const useMapZoom = () => useStore(useGeoViewStore(), (state) => state.mapState.zoom); export const useMapStoreActions = () => useStore(useGeoViewStore(), (state) => state.mapState.actions); diff --git a/packages/geoview-geochart/src/geochart-panel.tsx b/packages/geoview-geochart/src/geochart-panel.tsx index b667a11b80c..258c00eb4fc 100644 --- a/packages/geoview-geochart/src/geochart-panel.tsx +++ b/packages/geoview-geochart/src/geochart-panel.tsx @@ -1,12 +1,12 @@ import { useTheme } from '@mui/material/styles'; -import { TypeOrderedLayerInfo, TypeWindow, getLocalizedMessage } from 'geoview-core'; +import { TypeWindow, getLocalizedMessage } from 'geoview-core'; import { ChartType, SchemaValidator } from 'geochart'; import { LayerListEntry, Layout } from 'geoview-core/src/core/components/common'; import { TypeLayerData, TypeArrayOfLayerData } from 'geoview-core/src/api/events/payloads/get-feature-info-payload'; import { Typography } from 'geoview-core/src/ui/typography/typography'; import { Paper } from 'geoview-core/src/ui'; import { - useMapOrderedLayerInfo, + useMapVisibleLayers, useGeochartConfigs, useGeochartStoreActions, useGeochartStoreLayerDataArrayBatch, @@ -42,7 +42,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { // Get states and actions from store const configObj = useGeochartConfigs(); - const orderedLayerInfo = useMapOrderedLayerInfo() as TypeOrderedLayerInfo[]; + const visibleLayers = useMapVisibleLayers() as string[]; const storeArrayOfLayerData = useGeochartStoreLayerDataArrayBatch() as TypeArrayOfLayerData; const selectedLayerPath = useGeochartStoreSelectedLayerPath() as string; const { setSelectedLayerPath, setLayerDataArrayBatchLayerPathBypass } = useGeochartStoreActions(); @@ -102,13 +102,6 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { // Log logger.logTraceUseMemo('GEOCHART-PANEL - memoLayersList', storeArrayOfLayerData); - const visibleLayers = orderedLayerInfo - .map((layerInfo) => { - if (layerInfo.visible) return layerInfo.layerPath; - return undefined; - }) - .filter((layerPath) => layerPath !== undefined); - // Set the layers list return visibleLayers .map((layerPath) => storeArrayOfLayerData.find((layerData) => layerData.layerPath === layerPath)) @@ -125,7 +118,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { tooltip: `${layer!.layerName}, ${getNumFeaturesLabel(layer!)}`, } as LayerListEntry) ); - }, [orderedLayerInfo, storeArrayOfLayerData, configObj, getNumFeaturesLabel]); + }, [visibleLayers, storeArrayOfLayerData, configObj, getNumFeaturesLabel]); /** * Memoizes the selected layer for the LayerList component. diff --git a/packages/geoview-time-slider/src/time-slider-panel.tsx b/packages/geoview-time-slider/src/time-slider-panel.tsx index 17190b56a0b..15a6b35771a 100644 --- a/packages/geoview-time-slider/src/time-slider-panel.tsx +++ b/packages/geoview-time-slider/src/time-slider-panel.tsx @@ -1,7 +1,7 @@ import { useTheme } from '@mui/material/styles'; -import { TypeOrderedLayerInfo, TypeWindow, getLocalizedMessage } from 'geoview-core'; +import { TypeWindow, getLocalizedMessage } from 'geoview-core'; import { LayerListEntry, Layout } from 'geoview-core/src/core/components/common'; -import { useMapOrderedLayerInfo, useTimeSliderLayers } from 'geoview-core/src/core/stores'; +import { useMapVisibleLayers, useTimeSliderLayers } from 'geoview-core/src/core/stores'; import { Paper, Typography } from 'geoview-core/src/ui'; import { logger } from 'geoview-core/src/core/utils/logger'; @@ -33,7 +33,7 @@ export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element { const [selectedLayerPath, setSelectedLayerPath] = useState(); // get values from store - const orderedLayerInfo = useMapOrderedLayerInfo() as TypeOrderedLayerInfo[]; + const visibleLayers = useMapVisibleLayers() as string[]; const timeSliderLayers = useTimeSliderLayers(); /** @@ -53,13 +53,6 @@ export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element { // Log logger.logTraceUseMemo('TIME-SLIDER-PANEL - memoLayersList', timeSliderLayers); - const visibleLayers = orderedLayerInfo - .map((layerInfo) => { - if (layerInfo.visible) return layerInfo.layerPath; - return undefined; - }) - .filter((layerPath) => layerPath !== undefined); - // Return the layers return visibleLayers .map((layerPath) => { @@ -75,7 +68,7 @@ export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element { queryStatus: 'processed', } as LayerListEntry; }); - }, [orderedLayerInfo, timeSliderLayers]); + }, [visibleLayers, timeSliderLayers]); useEffect(() => { // Log