diff --git a/packages/geoview-core/public/configs/package-swiper-config-swiper.json b/packages/geoview-core/public/configs/package-swiper-config-swiper.json
index efa3163e56a..210358cb082 100644
--- a/packages/geoview-core/public/configs/package-swiper-config-swiper.json
+++ b/packages/geoview-core/public/configs/package-swiper-config-swiper.json
@@ -1,6 +1,6 @@
{
"orientation": "vertical",
"keyboardOffset": 10,
- "layers": ["esriFeatureLYR4"],
+ "layers": ["esriFeatureLYR4/0"],
"suportedLanguages": ["en", "fr"]
}
\ No newline at end of file
diff --git a/packages/geoview-core/public/configs/package-swiper2-config-swiper.json b/packages/geoview-core/public/configs/package-swiper2-config-swiper.json
index 42402264c4a..c3f4ace7e84 100644
--- a/packages/geoview-core/public/configs/package-swiper2-config-swiper.json
+++ b/packages/geoview-core/public/configs/package-swiper2-config-swiper.json
@@ -1,6 +1,6 @@
{
"orientation": "horizontal",
"keyboardOffset": 10,
- "layers": ["esriFeatureLYR4-map2", "esriDynamicLYR3-map2"],
+ "layers": ["esriFeatureLYR4-map2/2", "esriDynamicLYR3-map2/0"],
"suportedLanguages": ["en", "fr"]
}
\ No newline at end of file
diff --git a/packages/geoview-core/public/configs/package-swiper3-config-swiper.json b/packages/geoview-core/public/configs/package-swiper3-config-swiper.json
index 1af7ac7c116..220d9b4ca23 100644
--- a/packages/geoview-core/public/configs/package-swiper3-config-swiper.json
+++ b/packages/geoview-core/public/configs/package-swiper3-config-swiper.json
@@ -1,6 +1,6 @@
{
"orientation": "vertical",
"keyboardOffset": 10,
- "layers": ["swipe0", "swipe1", "swipe4", "swipe5", "swipe6", "rcs.ccc75c12-5acc-4a6a-959f-ef6f621147b9.en", "swipe7"],
+ "layers": ["swipe0/toner", "swipe1/msi-94-or-more", "swipe4/polygons.json", "swipe5/ec-msc:CURRENT_CONDITIONS", "swipe6/lakes", "rcs.ccc75c12-5acc-4a6a-959f-ef6f621147b9.en/0"],
"suportedLanguages": ["en", "fr"]
}
diff --git a/packages/geoview-core/src/api/event-processors/abstract-event-processor.ts b/packages/geoview-core/src/api/event-processors/abstract-event-processor.ts
index b229b908dd3..23511af8541 100644
--- a/packages/geoview-core/src/api/event-processors/abstract-event-processor.ts
+++ b/packages/geoview-core/src/api/event-processors/abstract-event-processor.ts
@@ -48,6 +48,7 @@ export abstract class AbstractEventProcessor {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected onInitialize(store: GeoviewStoreType): Array<() => void> | void {
+ // Here, `store` is unused, but used in inherited classes, so the eslint-disable should be kept
// This method should be overriden to initialize and return a list of subscribtions so that they can be destroyed later
return undefined;
}
diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts
index ef9cc9433bb..7035c02f621 100644
--- a/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts
+++ b/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts
@@ -57,7 +57,7 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
FeatureInfoEventProcessor.deleteFeatureAllInfo(store.getState().mapId, layerPath);
// Log
- logger.logDebug('Removed Feature Info in stores for layer path:', layerPath);
+ logger.logInfo('Removed Feature Info in stores for layer path:', layerPath);
}
});
}
diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts
index 846c0193e8a..07f5cdcc949 100644
--- a/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts
+++ b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts
@@ -47,9 +47,6 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
if (prevOrderedLayerPaths.includes(layerPath) && !curOrderedLayerPaths.includes(layerPath)) {
// Remove it
GeochartEventProcessor.removeGeochartChart(store.getState().mapId, layerPath);
-
- // Log
- logger.logDebug('Removed GeoChart configs for layer path:', layerPath);
}
});
}
@@ -95,18 +92,23 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
const chartData: GeoChartStoreByLayerPath = {};
// Loop on the charts
+ const layerPaths: string[] = [];
charts.forEach((chartInfo) => {
// For each layer path
chartInfo.layers.forEach((layer) => {
// Get the layer path
const layerPath = layer.layerId;
chartData[layerPath] = chartInfo;
+ layerPaths.push(layerPath);
});
});
// set store charts config
this.getGeochartState(mapId)?.actions.setGeochartCharts(chartData);
+ // Log
+ logger.logInfo('Added GeoChart configs for layer paths:', layerPaths);
+
// TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there)?
}
@@ -128,6 +130,9 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
// Update the layer data array in the store
this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...this.getGeochartState(mapId)?.geochartChartsConfig, ...toAdd });
+ // Log
+ logger.logInfo('Added GeoChart configs for layer path:', layerPath);
+
// TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there)?
}
@@ -153,6 +158,9 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
// Update the layer data array in the store
this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...chartConfigs });
+ // Log
+ logger.logInfo('Removed GeoChart configs for layer path:', layerPath);
+
// TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there)?
}
}
diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/swiper-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/swiper-event-processor.ts
new file mode 100644
index 00000000000..4753764dcd4
--- /dev/null
+++ b/packages/geoview-core/src/api/event-processors/event-processor-children/swiper-event-processor.ts
@@ -0,0 +1,169 @@
+import { GeoviewStoreType } from '@/core/stores';
+import { ISwiperState } from '@/core/stores/store-interface-and-intial-values/swiper-state';
+import { logger } from '@/core/utils/logger';
+
+import { AbstractEventProcessor } from '../abstract-event-processor';
+
+/**
+ * Event processor focusing on interacting with the swiper state in the store.
+ */
+export class SwiperEventProcessor extends AbstractEventProcessor {
+ // **********************************************************
+ // Static functions for Typescript files to access store actions
+ // **********************************************************
+ //! Typescript MUST always use the defined store actions below to modify store - NEVER use setState!
+ //! Some action does state modifications AND map actions.
+ //! ALWAYS use map event processor when an action modify store and IS NOT trap by map state event handler
+
+ /**
+ * Overrides initialization of the Swiper Event Processor
+ * @param {GeoviewStoreType} store The store associated with the Swiper Event Processor
+ * @returns An array of the subscriptions callbacks which were created
+ */
+ protected onInitialize(store: GeoviewStoreType): Array<() => void> | void {
+ // Checks for udpated layers in layer order
+ const unsubLayerRemoved = store.subscribe(
+ (state) => state.mapState.orderedLayerInfo,
+ (cur, prev) => {
+ // Log
+ logger.logTraceCoreStoreSubscription('SWIPER EVENT PROCESSOR - orderedLayerInfo', cur);
+
+ // Read the layer paths of each layer info
+ const curOrderedLayerPaths = cur.map((layerInfo) => layerInfo.layerPath);
+ const prevOrderedLayerPaths = prev.map((layerInfo) => layerInfo.layerPath);
+
+ // Get all the layer paths to check in a distinct array for looping purposes
+ const layerPathsToCheck = [...store.getState().swiperState.layerPaths];
+
+ // For each layer paths the swiper is using
+ layerPathsToCheck.forEach((layerPath) => {
+ // If it was in the layerdata array and is not anymore
+ if (prevOrderedLayerPaths.includes(layerPath) && !curOrderedLayerPaths.includes(layerPath)) {
+ // Remove it
+ SwiperEventProcessor.removeLayerPath(store.getState().mapId, layerPath);
+ }
+ });
+ }
+ );
+
+ return [unsubLayerRemoved];
+ }
+
+ /**
+ * Shortcut to get the Swiper state for a given map id
+ * @param {string} mapId The mapId
+ * @returns {ISwiperState | undefined} The Swiper state. Forcing the return to also be 'undefined', because
+ * there will be no swiperState if the Swiper plugin isn't active.
+ * This helps the developers making sure the existence is checked.
+ */
+ protected static getSwiperState(mapId: string): ISwiperState | undefined {
+ // Return the swiper state when it exists
+ return super.getState(mapId).swiperState;
+ }
+
+ /**
+ * Sets the layer paths on which the swiper should be activated.
+ *
+ * @param {string} mapId the map id
+ * @param {string[]} layerPaths The array of layer paths
+ */
+ static setLayerPaths(mapId: string, layerPaths: string[]): void {
+ // set store layer paths
+ this.getSwiperState(mapId)?.actions.setLayerPaths(layerPaths);
+
+ // Log
+ logger.logInfo('Added Swiper functionality for layer paths:', layerPaths);
+
+ // TODO: Also update the layer array in other store state to inform the later has a swiper attached to it?
+ }
+
+ /**
+ * Adds a swipe functionality to the specified map id and layer path
+ * @param {string} mapId The map ID
+ * @param {string} layerPath The layer path
+ */
+ static addLayerPath(mapId: string, layerPath: string): void {
+ // The processor needs an initialized layer paths store which is only initialized if the Swiper Plugin exists.
+ // Therefore, we validate its existence first.
+ if (!this.getSwiperState(mapId)) return;
+ if (!this.getSwiperState(mapId)?.layerPaths) return;
+
+ // If not already added
+ if (!this.getSwiperState(mapId)!.layerPaths.includes(layerPath)) {
+ // Add in the array
+ const updatedArray = [...this.getSwiperState(mapId)!.layerPaths];
+ updatedArray.push(layerPath);
+
+ // Update the layer data array in the store
+ this.getSwiperState(mapId)!.actions.setLayerPaths(updatedArray);
+
+ // Log
+ logger.logInfo('Added Swiper functionality for layer path:', layerPath);
+
+ // TODO: Also update the layer array in other store state to inform the later has a swiper attached to it?
+ } else {
+ // Log
+ logger.logInfo('Swiper functionality already active for layer path:', layerPath);
+ }
+ }
+
+ /**
+ * Removes a swipe functionality for the specified map id and layer path
+ * @param {string} mapId The map ID
+ * @param {string} layerPath The layer path
+ */
+ static removeLayerPath(mapId: string, layerPath: string): void {
+ // The processor needs an initialized layer paths store which is only initialized if the Swiper Plugin exists.
+ // Therefore, we validate its existence first.
+ if (!this.getSwiperState(mapId)) return;
+ if (!this.getSwiperState(mapId)?.layerPaths) return;
+
+ // Find the index with the layer path
+ const layerIndex = this.getSwiperState(mapId)!.layerPaths.findIndex((layer) => layer === layerPath);
+
+ // Config to remove
+ if (layerIndex !== undefined && layerIndex >= 0) {
+ // Remove from the array
+ const updatedArray = [...this.getSwiperState(mapId)!.layerPaths];
+ updatedArray.splice(layerIndex, 1);
+
+ // Update the layer data array in the store
+ this.getSwiperState(mapId)!.actions.setLayerPaths(updatedArray);
+
+ // Log
+ logger.logInfo('Removed Swiper functionality for layer path:', layerPath);
+
+ // TODO: Also update the layer array in other store state to inform the later has a swiper attached to it?
+ }
+ }
+
+ /**
+ * Removes the swipe functionality for all layer paths
+ * @param {string} mapId The map ID
+ */
+ static removeAll(mapId: string) {
+ // The processor needs an initialized layer paths store which is only initialized if the Swiper Plugin exists.
+ // Therefore, we validate its existence first.
+ if (!this.getSwiperState(mapId)) return;
+ if (!this.getSwiperState(mapId)?.layerPaths) return;
+
+ // Get all layer paths
+ const { layerPaths } = this.getSwiperState(mapId)!;
+
+ // Update the layer data array in the store
+ this.getSwiperState(mapId)!.actions.setLayerPaths([]);
+
+ // Log
+ logger.logInfo('Removed Swiper functionality for all layer paths', layerPaths);
+
+ // TODO: Also update the layer array in other store state to inform the later has a swiper attached to it?
+ }
+
+ // #endregion
+
+ // **********************************************************
+ // Static functions for Store Map State to action on API
+ // **********************************************************
+ //! NEVER add a store action who does set state AND map action at a same time.
+ //! Review the action in store state to make sure
+}
diff --git a/packages/geoview-core/src/api/event-processors/index.ts b/packages/geoview-core/src/api/event-processors/index.ts
index 3cfed4f4ef4..92c7a8ca53a 100644
--- a/packages/geoview-core/src/api/event-processors/index.ts
+++ b/packages/geoview-core/src/api/event-processors/index.ts
@@ -6,6 +6,7 @@ import { MapEventProcessor } from '@/api/event-processors/event-processor-childr
import { TimeSliderEventProcessor } from '@/api/event-processors/event-processor-children/time-slider-event-processor';
import { GeochartEventProcessor } from '@/api/event-processors/event-processor-children/geochart-event-processor';
import { DataTableProcessor } from '@/api/event-processors/event-processor-children/data-table-processor';
+import { SwiperEventProcessor } from './event-processor-children/swiper-event-processor';
// core
const appEventProcessor = new AppEventProcessor();
@@ -17,6 +18,7 @@ const dataTableProcessor = new DataTableProcessor();
// packages
const timeSliderEventProcessor = new TimeSliderEventProcessor();
const geochartEventProcessor = new GeochartEventProcessor();
+const swiperEventProcessor = new SwiperEventProcessor();
export function initializeEventProcessors(store: GeoviewStoreType) {
// core stores
@@ -30,6 +32,7 @@ export function initializeEventProcessors(store: GeoviewStoreType) {
// TODO: Change this check for something more generic that checks in appBar too
if (store.getState().mapConfig!.footerBar?.tabs.core.includes('time-slider')) timeSliderEventProcessor.initialize(store);
if (store.getState().mapConfig!.footerBar?.tabs.core.includes('geochart')) geochartEventProcessor.initialize(store);
+ if (store.getState().mapConfig!.corePackages?.includes('swiper')) swiperEventProcessor.initialize(store);
}
export function destroyEventProcessors(store: GeoviewStoreType) {
@@ -44,4 +47,5 @@ export function destroyEventProcessors(store: GeoviewStoreType) {
// TODO: Change this check for something more generic that checks in appBar too
if (store.getState().mapConfig!.footerBar?.tabs.core.includes('time-slider')) timeSliderEventProcessor.destroy();
if (store.getState().mapConfig!.footerBar?.tabs.core.includes('geochart')) geochartEventProcessor.destroy();
+ if (store.getState().mapConfig!.corePackages?.includes('swiper')) swiperEventProcessor.destroy();
}
diff --git a/packages/geoview-core/src/api/plugin/map-plugin.ts b/packages/geoview-core/src/api/plugin/map-plugin.tsx
similarity index 63%
rename from packages/geoview-core/src/api/plugin/map-plugin.ts
rename to packages/geoview-core/src/api/plugin/map-plugin.tsx
index 16a3197cfed..301210e18ee 100644
--- a/packages/geoview-core/src/api/plugin/map-plugin.ts
+++ b/packages/geoview-core/src/api/plugin/map-plugin.tsx
@@ -1,5 +1,6 @@
import { createRoot } from 'react-dom/client';
import { AbstractPlugin } from './abstract-plugin';
+import { MapContext } from '@/app';
/** ******************************************************************************************************************************
* Map Plugin abstract class.
@@ -24,19 +25,16 @@ export abstract class MapPlugin extends AbstractPlugin {
* Called when a map plugin is being added
*/
onAdd(): void {
- // If some layers set
- if ((this.configObj?.layers as string[]).length > 0) {
- // create the swiper container and insert it after top link
- const el = document.createElement('div');
- el.setAttribute('id', `${this.pluginProps.mapId}-${this.pluginId}`);
- const mapElement = document.getElementById(`mapbox-${this.pluginProps.mapId}`);
- mapElement?.insertBefore(el, mapElement.firstChild);
+ // create the swiper container and insert it after top link
+ const el = document.createElement('div');
+ el.setAttribute('id', `${this.pluginProps.mapId}-${this.pluginId}`);
+ const mapElement = document.getElementById(`mapbox-${this.pluginProps.mapId}`);
+ mapElement?.prepend(el);
- // create the swiper component and render
- const node = this.onCreateContent();
- const root = createRoot(document.getElementById(`${this.pluginProps.mapId}-${this.pluginId}`)!);
- root.render(node);
- }
+ // create the swiper component and render
+ const node = this.onCreateContent();
+ const root = createRoot(el);
+ root.render({node});
}
/**
diff --git a/packages/geoview-core/src/core/app-start.tsx b/packages/geoview-core/src/core/app-start.tsx
index c9d2c7ae6ef..d1b8550f428 100644
--- a/packages/geoview-core/src/core/app-start.tsx
+++ b/packages/geoview-core/src/core/app-start.tsx
@@ -50,7 +50,7 @@ function AppStart(props: AppStartProps): JSX.Element {
// Log
logger.logTraceUseMemo('APP-START - mapContextValue', mapId);
- return { mapId: mapId as string };
+ return { mapId };
}, [mapId]);
//! get store values by id because context is not set.... it is the only 2 atomic selector by id
diff --git a/packages/geoview-core/src/core/components/guide/guide-panel.tsx b/packages/geoview-core/src/core/components/guide/guide-panel.tsx
index 1e9b323a2a4..ef1ec8372b7 100644
--- a/packages/geoview-core/src/core/components/guide/guide-panel.tsx
+++ b/packages/geoview-core/src/core/components/guide/guide-panel.tsx
@@ -61,7 +61,7 @@ export function GuidePanel({ fullWidth }: GuidePanelType): JSX.Element {
const allTabs: TypeValidFooterBarTabsCoreProps | undefined = footerBarConfig?.tabs.core;
// fetch the content of general guide items with custom hook
- let mdFilePath = '/geoview/locales/markdown/general-content.md';
+ let mdFilePath = '/geoview/public/locales/markdown/general-content.md';
if (process.env.NODE_ENV === 'development') mdFilePath = '/locales/markdown/general-content.md';
useFetchAndParseMarkdown(mapId, mdFilePath, t('guide.errorMessage'), setLeftPanelHelpItems);
diff --git a/packages/geoview-core/src/core/stores/geoview-store.ts b/packages/geoview-core/src/core/stores/geoview-store.ts
index 08741fa7aa4..6cf759c5039 100644
--- a/packages/geoview-core/src/core/stores/geoview-store.ts
+++ b/packages/geoview-core/src/core/stores/geoview-store.ts
@@ -11,6 +11,7 @@ import { IMapState, initializeMapState } from './store-interface-and-intial-valu
import { IMapDataTableState, initialDataTableState } from './store-interface-and-intial-values/data-table-state';
import { ITimeSliderState, initializeTimeSliderState } from './store-interface-and-intial-values/time-slider-state';
import { IGeochartState, initializeGeochartState } from './store-interface-and-intial-values/geochart-state';
+import { ISwiperState, initializeSwiperState } from './store-interface-and-intial-values/swiper-state';
import { IUIState, initializeUIState } from './store-interface-and-intial-values/ui-state';
import { TypeMapFeaturesConfig } from '@/core/types/global-types';
@@ -38,6 +39,7 @@ export interface IGeoviewState {
// packages state interface
geochartState: IGeochartState;
timeSliderState: ITimeSliderState;
+ swiperState: ISwiperState;
}
export const geoviewStoreDefinition = (set: TypeSetStore, get: TypeGetStore) => {
@@ -61,6 +63,7 @@ export const geoviewStoreDefinition = (set: TypeSetStore, get: TypeGetStore) =>
// TODO: Change this check for something more generic that checks in appBar too
if (config.footerBar?.tabs.core.includes('time-slider')) set({ timeSliderState: initializeTimeSliderState(set, get) });
if (config.footerBar?.tabs.core.includes('geochart')) set({ geochartState: initializeGeochartState(set, get) });
+ if (config.corePackages?.includes('swiper')) set({ swiperState: initializeSwiperState(set, get) });
},
// core states
@@ -75,6 +78,7 @@ export const geoviewStoreDefinition = (set: TypeSetStore, get: TypeGetStore) =>
export const geoviewStoreDefinitionWithSubscribeSelector = subscribeWithSelector(geoviewStoreDefinition);
+// TODO: Refactor - Indicate why we need to use a fake store?
const fakeStore = create()(geoviewStoreDefinitionWithSubscribeSelector);
export type GeoviewStoreType = typeof fakeStore;
diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/swiper-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/swiper-state.ts
new file mode 100644
index 00000000000..6b6b27f04ab
--- /dev/null
+++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/swiper-state.ts
@@ -0,0 +1,52 @@
+import { useStore } from 'zustand';
+
+import { useGeoViewStore } from '../stores-managers';
+import { TypeGetStore, TypeSetStore } from '../geoview-store';
+
+// #region INTERFACES
+
+export interface ISwiperState {
+ layerPaths: string[];
+
+ actions: {
+ setLayerPaths: (layerPaths: string[]) => void;
+ };
+}
+
+// #endregion INTERFACES
+
+/**
+ * Initializes a Swiper state object.
+ * @param {TypeSetStore} set The store set callback function
+ * @param {TypeSetStore} get The store get callback function
+ * @returns {ISwiperState} The Swiper state object
+ */
+export function initializeSwiperState(set: TypeSetStore, get: TypeGetStore): ISwiperState {
+ const init = {
+ layerPaths: [],
+
+ // #region ACTIONS
+
+ actions: {
+ setLayerPaths(layerPaths: string[]) {
+ set({
+ swiperState: {
+ ...get().swiperState,
+ layerPaths,
+ },
+ });
+ },
+ },
+
+ // #endregion ACTIONS
+ } as ISwiperState;
+
+ return init;
+}
+
+// **********************************************************
+// Swiper state selectors
+// **********************************************************
+export const useSwiperLayerPaths = () => useStore(useGeoViewStore(), (state) => state.swiperState.layerPaths);
+
+export const useSwiperStoreActions = () => useStore(useGeoViewStore(), (state) => state.swiperState.actions);
diff --git a/packages/geoview-core/src/core/utils/config/config.ts b/packages/geoview-core/src/core/utils/config/config.ts
index 749289da116..8def967ebd0 100644
--- a/packages/geoview-core/src/core/utils/config/config.ts
+++ b/packages/geoview-core/src/core/utils/config/config.ts
@@ -1,12 +1,13 @@
/* eslint-disable no-console */
import { TypeDisplayLanguage, TypeListOfLayerEntryConfig, layerEntryIsGroupLayer } from '@/geo/map/map-schema-types';
import { CONST_LAYER_ENTRY_TYPE, TypeGeoviewLayerType } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
+import { logger } from '@/core/utils/logger';
+
import { TypeMapFeaturesConfig } from '../../types/global-types';
import { ConfigValidation } from './config-validation';
import { InlineDivConfigReader } from './reader/div-config-reader';
import { JsonConfigReader } from './reader/json-config-reader';
import { URLmapConfigReader } from './reader/url-config-reader';
-import { logger } from '@/core/utils/logger';
// ******************************************************************************************************************************
// ******************************************************************************************************************************
diff --git a/packages/geoview-core/src/geo/layer/layer.ts b/packages/geoview-core/src/geo/layer/layer.ts
index cd2ed72ab78..dd36d89e105 100644
--- a/packages/geoview-core/src/geo/layer/layer.ts
+++ b/packages/geoview-core/src/geo/layer/layer.ts
@@ -1,5 +1,5 @@
-/* eslint-disable no-param-reassign */
-
+import BaseLayer from 'ol/layer/Base';
+import LayerGroup from 'ol/layer/Group';
import { GeoCore, layerConfigIsGeoCore } from '@/geo/layer/other/geocore';
import { Geometry } from '@/geo/layer/geometry/geometry';
import { FeatureHighlight } from '@/geo/utils/feature-highlight';
@@ -301,8 +301,8 @@ export class Layer {
);
showError(this.mapId, message);
- // eslint-disable-next-line no-console
- console.log(`Duplicate use of geoview layer identifier ${geoviewLayerConfig.geoviewLayerId} on map ${this.mapId}`);
+ // Log
+ logger.logError(`Duplicate use of geoview layer identifier ${geoviewLayerConfig.geoviewLayerId} on map ${this.mapId}`);
}
/**
@@ -313,7 +313,16 @@ export class Layer {
* @returns {AbstractGeoViewLayer} Returns the geoview instance associated to the layer path.
*/
geoviewLayer(layerPath: string): AbstractGeoViewLayer {
+ // TODO: Refactor - Move this method next to the getGeoviewLayerByLayerPath equivalent. And then rename it?
+ // The first element of the layerPath is the geoviewLayerId
const geoviewLayerInstance = this.geoviewLayers[layerPath.split('/')[0]];
+
+ // TODO: Check #1857 - Why set the `layerPathAssociatedToTheGeoviewLayer` property on the fly like that? Should likely set this somewhere else than in this function that looks more like a getter.
+ // TO.DOCONT: It seems `layerPathAssociatedToTheGeoviewLayer` is indeed used many places, notably in applyFilters logic.
+ // TO.DOCONT: If all those places rely on the `layerPathAssociatedToTheGeoviewLayer` to be set, that logic using layerPathAssociatedToTheGeoviewLayer should be moved over there.
+ // TO.DOCONT: If there's more other places relying on the `layerPathAssociatedToTheGeoviewLayer`, then it's not ideal,
+ // TO.DOCONT: because it's assuming/relying on the fact that all those other places use this specific geoviewLayer() prior to do their work.
+ // TO.DOCONT: There's likely some separation of logic to apply here. Make this function more evident that it 'sets' something, not just 'gets' a GeoViewLayer.
geoviewLayerInstance.layerPathAssociatedToTheGeoviewLayer = layerPath;
return geoviewLayerInstance;
}
@@ -394,6 +403,9 @@ export class Layer {
(geoviewLayerConfig) => geoviewLayerConfig.geoviewLayerId !== partialLayerPath
);
}
+
+ // Log
+ logger.logInfo(`Layer removed for ${partialLayerPath}`);
};
/**
@@ -471,7 +483,7 @@ export class Layer {
* Asynchronously gets a layer using its id and return the layer data.
* If the layer we're searching for has to be processed, set mustBeProcessed to true when awaiting on this method.
* This function waits the timeout period before abandonning (or uses the default timeout when not provided).
- * Note this function uses the 'Async' suffix only to differentiate it from 'getGeoviewLayerById'.
+ * Note this function uses the 'Async' suffix to differentiate it from 'getGeoviewLayerById'.
*
* @param {string} layerID the layer id to look for
* @param {string} mustBeProcessed indicate if the layer we're searching for must be found only once processed
@@ -508,6 +520,40 @@ export class Layer {
throw new Error(`Layer ${geoviewLayerId} not found.`);
};
+ /**
+ * Returns the OpenLayer layer associated to a specific layer path.
+ * @param {string} layerPath The layer path to the layer's configuration.
+ *
+ * @returns {BaseLayer | LayerGroup} Returns the OpenLayer layer associated to the layer path.
+ */
+ getLayerByLayerPath = (layerPath: string): BaseLayer | LayerGroup => {
+ // Return the olLayer object from the registered layers
+ const olLayer = api.maps[this.mapId].layer.registeredLayers[layerPath]?.olLayer;
+ if (olLayer) return olLayer;
+ throw new Error(`Layer at path ${layerPath} not found.`);
+ };
+
+ /**
+ * Asynchronously returns the OpenLayer layer associated to a specific layer path.
+ * This function waits the timeout period before abandonning (or uses the default timeout when not provided).
+ * Note this function uses the 'Async' suffix to differentiate it from 'getLayerByLayerPath'.
+ * @param {string} layerPath The layer path to the layer's configuration.
+ *
+ * @returns {BaseLayer | LayerGroup} Returns the OpenLayer layer associated to the layer path.
+ */
+ getLayerByLayerPathAsync = async (layerPath: string, timeout?: number, checkFrequency?: number): Promise => {
+ // Make sure the open layer has been created, sometimes it can still be in the process of being created
+ const promisedLayer = await whenThisThen(
+ () => {
+ return api.maps[this.mapId].layer.registeredLayers[layerPath]?.olLayer;
+ },
+ timeout,
+ checkFrequency
+ );
+ // Here, the layer resolved
+ return promisedLayer!;
+ };
+
/**
* Returns a Promise that will be resolved once the given layer is in a processed phase.
* This function waits the timeout period before abandonning (or uses the default timeout when not provided).
diff --git a/packages/geoview-core/src/geo/map/map-viewer.ts b/packages/geoview-core/src/geo/map/map-viewer.ts
index 8d6ccd8b7f8..0086dc3881b 100644
--- a/packages/geoview-core/src/geo/map/map-viewer.ts
+++ b/packages/geoview-core/src/geo/map/map-viewer.ts
@@ -56,6 +56,7 @@ import { MapEventProcessor } from '@/api/event-processors/event-processor-childr
import { AppEventProcessor } from '@/api/event-processors/event-processor-children/app-event-processor';
import { logger } from '@/core/utils/logger';
+// TODO: Refactor - Typo TypeDcoument - actually, remove the type altogether, doesn't seem useful
interface TypeDcoument extends Document {
webkitExitFullscreen: () => void;
msExitFullscreen: () => void;
@@ -115,8 +116,15 @@ export class MapViewer {
private i18nInstance!: i18n;
/**
- * Add the map instance to the maps array in the api
- *
+ * Constructor for a MapViewer, setting:
+ * - the mapId
+ * - the mapFeaturesConfig
+ * - i18n
+ * - appbar, navbar, footerbar
+ * - modalApi
+ * - geoviewRenderer
+ * - basemap
+ * - layers
* @param {TypeMapFeaturesConfig} mapFeaturesConfig map properties
* @param {i18n} i18instance language instance
*/
@@ -142,6 +150,26 @@ export class MapViewer {
this.setLayerAddedListener4ThisListOfLayer(listOfGeoviewLayerConfig);
}
+ /**
+ * Initializes map, layer class and geometries
+ *
+ * @param {OLMap} cgpMap The OpenLayers map object
+ */
+ initMap(cgpMap: OLMap): void {
+ // Set the map
+ this.map = cgpMap;
+
+ // TODO: Refactor - Is it necessary to set the mapId again? It was set in constructor. Preferably set it at one or the other.
+ this.mapId = cgpMap.get('mapId');
+
+ // initialize layers and load the layers passed in from map config if any
+ this.layer = new Layer(this.mapId);
+ this.layer.loadListOfGeoviewLayer(this.mapFeaturesConfig.map.listOfGeoviewLayerConfig);
+
+ // check if geometries are provided from url
+ this.loadGeometries();
+ }
+
/**
* Set the layer added event listener and timeout function for the list of geoview layer configurations.
*
@@ -159,6 +187,10 @@ export class MapViewer {
if (payloadIsGeoViewLayerAdded(payload)) {
const { geoviewLayer } = payload;
+
+ // Log
+ logger.logInfo(`GeoView Layer added on map ${geoviewLayer.geoviewLayerId}`, geoviewLayer);
+
MapEventProcessor.setLayerZIndices(this.mapId);
// If metadata are processed
if (geoviewLayer.allLayerStatusAreIn(['processed', 'loading', 'loaded', 'error'])) {
@@ -174,10 +206,10 @@ export class MapViewer {
}
/**
- * Method used to test all geoview layers status flags to determine if all the metadata of the map are loaded.
+ * Tests all geoview layers status flags to determine if all the metadata of the map are loaded.
* This doesn't mean that all the layers are loaded on the map, Only the metadata are read and processed.
*
- * @returns true if all geoview layers on the map are loaded or detected as a load error.
+ * @returns {boolean} true if all geoview layers on the map are loaded or detected as a load error.
*/
mapIsReady(): boolean {
if (this.layer === undefined) return false;
@@ -219,23 +251,6 @@ export class MapViewer {
}, 250);
}
- /**
- * Initialize layers, basemap and projection
- *
- * @param cgpMap
- */
- initMap(cgpMap: OLMap): void {
- this.mapId = cgpMap.get('mapId');
- this.map = cgpMap;
-
- // initialize layers and load the layers passed in from map config if any
- this.layer = new Layer(this.mapId);
- this.layer.loadListOfGeoviewLayer(this.mapFeaturesConfig.map.listOfGeoviewLayerConfig);
-
- // check if geometries are provided from url
- this.loadGeometries();
- }
-
/**
* Add a new custom component to the map
*
@@ -243,6 +258,7 @@ export class MapViewer {
* @param {JSX.Element} component the component to add
*/
addComponent(mapComponentId: string, component: JSX.Element): void {
+ // TODO: Refactor - Doesn't seem to be used anymore, keep? If keep it, refactor to call a function instead of event.emit.
if (mapComponentId && component) {
// emit an event to add the component
api.event.emit(mapComponentPayload(EVENT_NAMES.MAP.EVENT_MAP_ADD_COMPONENT, this.mapId, mapComponentId, component));
@@ -255,6 +271,7 @@ export class MapViewer {
* @param imapComponentIdd the id of the component to remove
*/
removeComponent(mapComponentId: string): void {
+ // TODO: Refactor - Doesn't seem to be used anymore, keep? If keep it, refactor to call a function instead of event.emit.
if (mapComponentId) {
// emit an event to add the component
api.event.emit(mapComponentPayload(EVENT_NAMES.MAP.EVENT_MAP_REMOVE_COMPONENT, this.mapId, mapComponentId));
@@ -318,6 +335,8 @@ export class MapViewer {
* @param {HTMLElement} element the element to toggle fullscreen on
*/
setFullscreen(status: boolean, element: TypeHTMLElement): void {
+ // TODO: Refactor - For reusability, this function should be static and moved to a browser-utilities class
+ // TO.DOCONT: If we want to keep a function here, in MapViewer, it should just be a redirect to the browser-utilities'
// enter fullscreen
if (status) {
if (element.requestFullscreen) {
diff --git a/packages/geoview-geochart/src/index.tsx b/packages/geoview-geochart/src/index.tsx
index e78415b9004..cfb9c32f7ff 100644
--- a/packages/geoview-geochart/src/index.tsx
+++ b/packages/geoview-geochart/src/index.tsx
@@ -56,6 +56,9 @@ class GeoChartFooterPlugin extends FooterPlugin {
},
});
+ /**
+ * Overrides the addition of the GeoChart Footer Plugin to make sure to set the chart configs into the store.
+ */
onAdd(): void {
// Initialize the store with geochart provided configuration
GeochartEventProcessor.setGeochartCharts(this.pluginProps.mapId, this.configObj.charts);
@@ -64,6 +67,10 @@ class GeoChartFooterPlugin extends FooterPlugin {
super.onAdd();
}
+ /**
+ * Overrides the creation of the content properties of this GeoChart Footer Plugin.
+ * @returns {TypeTabs} The TypeTabs for the GeoChart Footer Plugin
+ */
onCreateContentProps(): TypeTabs {
// Create element
const content = ;
@@ -77,6 +84,10 @@ class GeoChartFooterPlugin extends FooterPlugin {
};
}
+ /**
+ * Overrides when the plugin is selected in the Footer Bar.
+ * @returns {TypeTabs} The TypeTabs for the GeoChart Footer Plugin
+ */
onSelected(): void {
// Call parent
super.onSelected();
diff --git a/packages/geoview-layers-panel/src/layers-list.tsx b/packages/geoview-layers-panel/src/layers-list.tsx
index b37eb11304e..8b20706d781 100644
--- a/packages/geoview-layers-panel/src/layers-list.tsx
+++ b/packages/geoview-layers-panel/src/layers-list.tsx
@@ -12,6 +12,7 @@ import {
} from 'geoview-core';
import { sxClasses } from './layers-list.style';
+
/**
* interface for the layers list properties in layers panel
*/
diff --git a/packages/geoview-swiper/src/index.tsx b/packages/geoview-swiper/src/index.tsx
index bf7acee911d..65909f11223 100644
--- a/packages/geoview-swiper/src/index.tsx
+++ b/packages/geoview-swiper/src/index.tsx
@@ -1,5 +1,7 @@
import { Cast, toJsonObject, TypeJsonObject, AnySchemaObject } from 'geoview-core';
import { MapPlugin } from 'geoview-core/src/api/plugin/map-plugin';
+import { SwiperEventProcessor } from 'geoview-core/src/api/event-processors/event-processor-children/swiper-event-processor';
+import { logger } from 'geoview-core/src/core/utils/logger';
import schema from '../schema.json';
import defaultConfig from '../default-config-swiper.json';
@@ -10,21 +12,21 @@ import { Swiper } from './swiper';
*/
class SwiperPlugin extends MapPlugin {
/**
- * Return the package schema
+ * Returns the package schema
*
* @returns {AnySchemaObject} the package schema
*/
schema = (): AnySchemaObject => schema;
/**
- * Return the default config for this package
+ * Returns the default config for this package
*
* @returns {TypeJsonObject} the default config
*/
defaultConfig = (): TypeJsonObject => toJsonObject(defaultConfig);
/**
- * translations object to inject to the viewer translations
+ * Translations object to inject to the viewer translations
*/
translations = toJsonObject({
en: {
@@ -41,9 +43,57 @@ class SwiperPlugin extends MapPlugin {
},
});
+ /**
+ * Overrides the addition of the Swiper Map Plugin to make sure to set the layer paths from the config into the store.
+ */
+ onAdd(): void {
+ // Initialize the store with swiper provided configuration
+ SwiperEventProcessor.setLayerPaths(this.pluginProps.mapId, this.configObj.layers);
+
+ // Call parent
+ super.onAdd();
+ }
+
+ /**
+ * Overrides the creation of the content of this Swiper Map Plugin.
+ * @returns {JSX.Element} The JSX.Element representing the Swiper Plugin
+ */
onCreateContent(): JSX.Element {
return ;
}
+
+ /**
+ * Activates the swiper for the layer indicated by the given layer path.
+ * @param {string} layerPath The layer path to activate swiper functionality
+ */
+ activateForLayer = (layerPath: string) => {
+ // Check if the layer exists on the map
+ const layer = this.map().layer.getLayerByLayerPath(layerPath);
+ if (layer) {
+ // Add the layer path
+ SwiperEventProcessor.addLayerPath(this.pluginProps.mapId, layerPath);
+ } else {
+ // Log
+ logger.logError(`Couldn't find the layer with layer path ${layerPath}`);
+ }
+ };
+
+ /**
+ * Deactivates the swiper for the layer indicated by the given layer path.
+ * @param {string} layerPath The layer path to deactivate swiper functionality
+ */
+ deActivateForLayer = (layerPath: string) => {
+ // Remove the layer
+ SwiperEventProcessor.removeLayerPath(this.pluginProps.mapId, layerPath);
+ };
+
+ /**
+ * Deactivates the swiper for the layer indicated by the given layer path.
+ */
+ deActivateAll = () => {
+ // Remove all layers
+ SwiperEventProcessor.removeAll(this.pluginProps.mapId);
+ };
}
export default SwiperPlugin;
diff --git a/packages/geoview-swiper/src/swiper-style.ts b/packages/geoview-swiper/src/swiper-style.ts
new file mode 100644
index 00000000000..4fd811a538b
--- /dev/null
+++ b/packages/geoview-swiper/src/swiper-style.ts
@@ -0,0 +1,70 @@
+export const sxClasses = {
+ layerSwipe: {
+ position: 'absolute',
+ width: '100%',
+ height: '100%',
+ },
+
+ handle: {
+ backgroundColor: 'rgba(50,50,50,0.75)',
+ color: '#fff',
+ width: '24px',
+ height: '24px',
+ },
+
+ bar: {
+ position: 'absolute',
+ backgroundColor: 'rgba(50,50,50,0.75)',
+ zIndex: 151,
+ boxSizing: 'content-box',
+ margin: 0,
+ padding: '0!important',
+ },
+
+ vertical: {
+ width: '8px',
+ height: '100%',
+ cursor: 'col-resize',
+ top: '0px!important',
+
+ '& .handleContainer': {
+ position: 'relative',
+ width: '58px',
+ height: '24px',
+ zIndex: 1,
+ top: '50%',
+ left: '-25px',
+
+ '& .handleR': {
+ transform: 'rotate(90deg)',
+ float: 'right',
+ },
+
+ '& .handleL': {
+ transform: 'rotate(90deg)',
+ float: 'left',
+ },
+ },
+ },
+
+ horizontal: {
+ width: '100%',
+ height: '8px',
+ cursor: 'col-resize',
+ left: '0px!important',
+
+ '& .handleContainer': {
+ position: 'relative',
+ height: '58px',
+ width: '24px',
+ zIndex: 1,
+ left: '50%',
+ top: '-24px',
+
+ '& .handleL': {
+ verticalAlign: 'top',
+ marginBottom: '8px',
+ },
+ },
+ },
+};
diff --git a/packages/geoview-swiper/src/swiper.tsx b/packages/geoview-swiper/src/swiper.tsx
index c908bd32c85..029e33910ea 100644
--- a/packages/geoview-swiper/src/swiper.tsx
+++ b/packages/geoview-swiper/src/swiper.tsx
@@ -1,93 +1,20 @@
import Draggable from 'react-draggable';
-import { RefObject, useAppDisplayLanguageById } from 'geoview-core';
-
+import { RefObject } from 'geoview-core';
+import { MapViewer } from 'geoview-core/src/geo/map/map-viewer';
+import { useSwiperLayerPaths } from 'geoview-core/src/core/stores/store-interface-and-intial-values/swiper-state';
import { getLocalizedMessage } from 'geoview-core/src/core/utils/utilities';
-import { EVENT_NAMES } from 'geoview-core/src/api/events/event-types';
-import { PayloadBaseClass, TypeResultsSet, payloadIsLayerSetUpdated } from 'geoview-core/src/api/events/payloads';
import { logger } from 'geoview-core/src/core/utils/logger';
import { getRenderPixel } from 'ol/render';
-import Map from 'ol/Map';
import RenderEvent from 'ol/render/Event';
import BaseLayer from 'ol/layer/Base';
-import { VectorImage } from 'ol/layer';
-import VectorSource from 'ol/source/Vector';
import { EventTypes } from 'ol/Observable';
import BaseEvent from 'ol/events/Event';
import debounce from 'lodash/debounce';
-const sxClasses = {
- layerSwipe: {
- position: 'absolute',
- width: '100%',
- height: '100%',
- },
-
- handle: {
- backgroundColor: 'rgba(50,50,50,0.75)',
- color: '#fff',
- width: '24px',
- height: '24px',
- },
-
- bar: {
- position: 'absolute',
- backgroundColor: 'rgba(50,50,50,0.75)',
- zIndex: 151,
- boxSizing: 'content-box',
- margin: 0,
- padding: '0!important',
- },
-
- vertical: {
- width: '8px',
- height: '100%',
- cursor: 'col-resize',
- top: '0px!important',
-
- '& .handleContainer': {
- position: 'relative',
- width: '58px',
- height: '24px',
- zIndex: 1,
- top: '50%',
- left: '-25px',
-
- '& .handleR': {
- transform: 'rotate(90deg)',
- float: 'right',
- },
-
- '& .handleL': {
- transform: 'rotate(90deg)',
- float: 'left',
- },
- },
- },
-
- horizontal: {
- width: '100%',
- height: '8px',
- cursor: 'col-resize',
- left: '0px!important',
-
- '& .handleContainer': {
- position: 'relative',
- height: '58px',
- width: '24px',
- zIndex: 1,
- left: '50%',
- top: '-24px',
-
- '& .handleL': {
- verticalAlign: 'top',
- marginBottom: '8px',
- },
- },
- },
-};
+import { sxClasses } from './swiper-style';
type SwiperProps = {
mapId: string;
@@ -104,65 +31,53 @@ export function Swiper(props: SwiperProps): JSX.Element {
const { cgpv } = window;
const { api, ui, react } = cgpv;
- const { useEffect, useState, useRef } = react;
-
+ const { useEffect, useState, useRef, useCallback } = react;
const { Box, Tooltip, HandleIcon } = ui.elements;
+ const { orientation } = config;
+ const mapViewer = api.maps[mapId] as MapViewer;
- const [map] = useState