Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cgpv) - Introduction of 4 distinct callbacks for cgpv. #2546

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 123 additions & 60 deletions packages/geoview-core/public/templates/demos/demo-function-event.html

Large diffs are not rendered by default.

110 changes: 88 additions & 22 deletions packages/geoview-core/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export const api = new API();

const reactRoot: Record<string, Root> = {};

let cgpvCallbackMapInit: (mapId: string) => void | undefined;
let cgpvCallbackMapReady: (mapId: string) => void | undefined;
let cgpvCallbackLayersProcessed: (mapId: string) => void | undefined;
let cgpvCallbackLayersLoaded: (mapId: string) => void | undefined;

/**
* Function to unmount a map element
*
Expand Down Expand Up @@ -204,11 +209,10 @@ export async function initMapDivFromFunctionCall(mapDiv: HTMLElement, mapConfig:
}

/**
* Initialize the cgpv and render it to root element
* Initializes the cgpv and render it to root element
*
* @param {(mapId: string) => void} callbackMapInit optional callback function to run once the map rendering is ready
* @param {(mapId: string) => void} callbackMapLayersLoaded optional callback function to run once layers are loaded on the map
* @returns {Promise<void>}
*/
function init(callbackMapInit?: (mapId: string) => void, callbackMapLayersLoaded?: (mapId: string) => void): void {
const mapElements = document.getElementsByClassName('geoview-map');
Expand All @@ -220,31 +224,53 @@ function init(callbackMapInit?: (mapId: string) => void, callbackMapLayersLoaded
// Render the map
const promiseMapInit = renderMap(mapElement);

// The callback for the map init when the promiseMapInit will resolve
const theCallbackMapInit = cgpvCallbackMapInit;

// The callback for the map ready when the promiseMapInit will resolve
const theCallbackMapReady = cgpvCallbackMapReady;

// The callback for the layers processed when the promiseMapInit will resolve
const theCallbackLayersProcessed = cgpvCallbackLayersProcessed;

// The callback for the layers loaded when the promiseMapInit will resolve
const theCallbackLayersLoaded = cgpvCallbackLayersLoaded;

// When the map init is done
promiseMapInit
.then(() => {
// Log
logger.logInfo('Map initialized', mapElement.getAttribute('id')!);

// TODO: Fix this timeout issue when geoCore layer are use in config: https://github.com/Canadian-Geospatial-Platform/geoview/issues/2380
// Set a timeout value if one of thelaeyrs is a geoCore type
const mapId = mapElement.getAttribute('id')!;
const layerTypes = api.maps[mapId].mapFeaturesConfig.map.listOfGeoviewLayerConfig?.map((item) => item.geoviewLayerType) || [];
const geoCoreTimeout = layerTypes.includes('geoCore') ? 500 : 0;

// TODO: Fix this timeout issue when geoCore layer are use in config: https://github.com/Canadian-Geospatial-Platform/geoview/issues/2380
setTimeout(() => {
// Callback about it
callbackMapInit?.(mapId);

// Register when the map viewer will have loaded layers
api.maps[mapId].onMapLayersLoaded((mapViewerLoaded) => {
logger.logInfo('Map layers loaded', mapViewerLoaded.mapId);

// Callback for that particular map
callbackMapLayersLoaded?.(mapViewerLoaded.mapId);
});
}, geoCoreTimeout);
logger.logInfo('Map initialized', mapId);

// Callback about it
theCallbackMapInit?.(mapId);
callbackMapInit?.(mapId); // TODO: Obsolete call, remove it eventually

// Register when the map viewer will have a map ready
api.maps[mapId].onMapReady((mapViewer) => {
logger.logInfo('Map ready / layers registered', mapViewer.mapId);

// Callback for that particular map
theCallbackMapReady?.(mapViewer.mapId);
});

// Register when the map viewer will have loaded layers
api.maps[mapId].onMapLayersProcessed((mapViewer) => {
logger.logInfo('Map layers processed', mapViewer.mapId);

// Callback for that particular map
theCallbackLayersProcessed?.(mapViewer.mapId);
});

// Register when the map viewer will have loaded layers
api.maps[mapId].onMapLayersLoaded((mapViewer) => {
logger.logInfo('Map layers loaded', mapViewer.mapId);

// Callback for that particular map
theCallbackLayersLoaded?.(mapViewer.mapId);
callbackMapLayersLoaded?.(mapViewer.mapId); // TODO: Obsolete call, remove it eventually
});
})
.catch((error) => {
// Log
Expand All @@ -254,9 +280,49 @@ function init(callbackMapInit?: (mapId: string) => void, callbackMapLayersLoaded
}
}

/**
* Registers a callback when the map has been initialized
* @param {(mapId: string) => void} callback - The callback to be called
*/
export function onMapInit(callback: (mapId: string) => void): void {
// Keep the callback
cgpvCallbackMapInit = callback;
}

/**
* Registers a callback when the map has turned ready / layers were registered
* @param {(mapId: string) => void} callback - The callback to be called
*/
export function onMapReady(callback: (mapId: string) => void): void {
// Keep the callback
cgpvCallbackMapReady = callback;
}

/**
* Registers a callback when the layers have been processed
* @param {(mapId: string) => void} callback - The callback to be called
*/
export function onLayersProcessed(callback: (mapId: string) => void): void {
// Keep the callback
cgpvCallbackLayersProcessed = callback;
}

/**
* Registers a callback when the layers have been loaded
* @param {(mapId: string) => void} callback - The callback to be called
*/
export function onLayersLoaded(callback: (mapId: string) => void): void {
// Keep the callback
cgpvCallbackLayersLoaded = callback;
}

// cgpv object to be exported with the api for outside use
export const cgpv: TypeCGPV = {
init,
onMapInit,
onMapReady,
onLayersProcessed,
onLayersLoaded,
api,
react: React,
createRoot,
Expand Down
5 changes: 5 additions & 0 deletions packages/geoview-core/src/core/types/global-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export interface TypeWindow extends Window {
*/
export type TypeCGPV = {
init: CGPVInitCallback;
onMapInit: CGPVCallback;
onMapReady: CGPVCallback;
onLayersProcessed: CGPVCallback;
onLayersLoaded: CGPVCallback;
api: API;
react: typeof React;
createRoot: typeof createRoot;
Expand All @@ -64,6 +68,7 @@ export type TypeCGPV = {
* Type used for a callback function.
*/
export type CGPVInitCallback = (callbackMapsInit?: (mapId: string) => void, callbackMapsLayersLoaded?: (mapId: string) => void) => void;
export type CGPVCallback = (callback: (mapId: string) => void) => void;

/** ******************************************************************************************************************************
* Type used for exporting UI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,15 +408,15 @@ export class GVEsriDynamic extends AbstractGVRaster {
if (i === 0) {
if (styleSettings.classBreakStyleInfo[0].visible !== false && styleSettings.defaultVisible === false)
filterArray.push(
`${styleSettings.field} >= ${this.#formatFieldValue(
`${styleSettings.field} >= ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[0].minValue!,
layerConfig.source.featureInfo!
)}`
);
else if (styleSettings.classBreakStyleInfo[0].visible === false && styleSettings.defaultVisible !== false) {
filterArray.push(
`${styleSettings.field} < ${this.#formatFieldValue(
`${styleSettings.field} < ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[0].minValue!,
layerConfig.source.featureInfo!
Expand All @@ -426,23 +426,23 @@ export class GVEsriDynamic extends AbstractGVRaster {
}
} else if (styleSettings.classBreakStyleInfo[i].visible !== false && styleSettings.defaultVisible === false) {
filterArray.push(
`${styleSettings.field} > ${this.#formatFieldValue(
`${styleSettings.field} > ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i].minValue!,
layerConfig.source.featureInfo!
)}`
);
if (i + 1 === styleSettings.classBreakStyleInfo.length)
filterArray.push(
`${styleSettings.field} <= ${this.#formatFieldValue(
`${styleSettings.field} <= ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i].maxValue!,
layerConfig.source.featureInfo!
)}`
);
} else if (styleSettings.classBreakStyleInfo[i].visible === false && styleSettings.defaultVisible !== false) {
filterArray.push(
`${styleSettings.field} <= ${this.#formatFieldValue(
`${styleSettings.field} <= ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i].minValue!,
layerConfig.source.featureInfo!
Expand All @@ -453,15 +453,15 @@ export class GVEsriDynamic extends AbstractGVRaster {
} else if (styleSettings.defaultVisible === false) {
if (styleSettings.classBreakStyleInfo[i].visible === false) {
filterArray.push(
`${styleSettings.field} <= ${this.#formatFieldValue(
`${styleSettings.field} <= ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i - 1].maxValue!,
layerConfig.source.featureInfo!
)}`
);
} else if (i + 1 === styleSettings.classBreakStyleInfo.length) {
filterArray.push(
`${styleSettings.field} <= ${this.#formatFieldValue(
`${styleSettings.field} <= ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i].maxValue!,
layerConfig.source.featureInfo!
Expand All @@ -470,7 +470,7 @@ export class GVEsriDynamic extends AbstractGVRaster {
}
} else if (styleSettings.classBreakStyleInfo[i].visible !== false) {
filterArray.push(
`${styleSettings.field} > ${this.#formatFieldValue(
`${styleSettings.field} > ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[i - 1].maxValue!,
layerConfig.source.featureInfo!
Expand All @@ -483,7 +483,7 @@ export class GVEsriDynamic extends AbstractGVRaster {
}
if (visibleWhenGreatherThisIndex !== -1)
filterArray.push(
`${styleSettings.field} > ${this.#formatFieldValue(
`${styleSettings.field} > ${GVEsriDynamic.#formatFieldValue(
styleSettings.field,
styleSettings.classBreakStyleInfo[visibleWhenGreatherThisIndex].maxValue!,
layerConfig.source.featureInfo!
Expand Down Expand Up @@ -613,7 +613,7 @@ export class GVEsriDynamic extends AbstractGVRaster {
): string {
let queryString = styleSettings.defaultVisible !== false && !level ? 'not (' : '(';
for (let i = 0; i < queryTree.length; i++) {
const value = this.#formatFieldValue(styleSettings.fields[fieldOrder[level]], queryTree[i].fieldValue, sourceFeatureInfo);
const value = GVEsriDynamic.#formatFieldValue(styleSettings.fields[fieldOrder[level]], queryTree[i].fieldValue, sourceFeatureInfo);
// The nextField array is not empty, then it is is not the last field
if (queryTree[i].nextField.length) {
// If i > 0 (true) then we add a OR clause
Expand Down Expand Up @@ -644,7 +644,7 @@ export class GVEsriDynamic extends AbstractGVRaster {
* @returns {string} The resulting field value.
* @private
*/
#formatFieldValue(fieldName: string, rawValue: string | number | Date, sourceFeatureInfo: TypeFeatureInfoLayerConfig): string {
static #formatFieldValue(fieldName: string, rawValue: string | number | Date, sourceFeatureInfo: TypeFeatureInfoLayerConfig): string {
const fieldEntry = sourceFeatureInfo.outfields?.find((outfield) => outfield.name === fieldName);
const fieldType = fieldEntry?.type;
switch (fieldType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export class GVWMS extends AbstractGVRaster {
}
} else featureMember = { plain_text: { '#text': response.data } };
if (featureMember) {
const featureInfoResult = this.#formatWmsFeatureInfoResult(featureMember, clickCoordinate);
const featureInfoResult = GVWMS.#formatWmsFeatureInfoResult(featureMember, clickCoordinate);
return featureInfoResult;
}
}
Expand Down Expand Up @@ -401,7 +401,7 @@ export class GVWMS extends AbstractGVRaster {
* @returns {TypeFeatureInfoEntry[]} The feature info table.
* @private
*/
#formatWmsFeatureInfoResult(featureMember: TypeJsonObject, clickCoordinate: Coordinate): TypeFeatureInfoEntry[] {
static #formatWmsFeatureInfoResult(featureMember: TypeJsonObject, clickCoordinate: Coordinate): TypeFeatureInfoEntry[] {
const queryResult: TypeFeatureInfoEntry[] = [];

let featureKeyCounter = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export abstract class AbstractLayerSet {
// Keep all callback delegates references
#onLayerSetUpdatedHandlers: LayerSetUpdatedDelegate[] = [];

// Keep all callback delegates references
#onLayerStatusUpdatedHandlers: LayerStatusUpdatedDelegate[] = [];

// Keep a bounded reference to the handle layer status changed
#boundHandleLayerStatusChanged: (config: ConfigBaseClass, layerStatusEvent: LayerStatusChangedEvent) => void;

Expand Down Expand Up @@ -140,13 +143,16 @@ export abstract class AbstractLayerSet {

// If the layer could be found
if (layer) {
// Register the layer automatically in the layer set
// Register the layer itself (not the layer config) (recall the hybrid mode) automatically in the layer set
this.registerLayer(layer, layerConfig.layerPath).catch((error) => {
// Log
logger.logPromiseFailed('in registerLayer in registerLayerConfig', error);
});
}
}

// Emit that the layerConfig got their status changed
this.#emitLayerStatusUpdated({ layer: layerConfig });
} catch (error) {
// Error happened when trying to register the layer coming from the layer config
logger.logError('Error trying to register the layer coming from the layer config', error);
Expand Down Expand Up @@ -517,6 +523,34 @@ export abstract class AbstractLayerSet {
// Unregister the layersetupdated event callback
EventHelper.offEvent(this.#onLayerSetUpdatedHandlers, callback);
}

/**
* Emits an event to all registered handlers.
* @param {LayerStatusUpdatedEvent} event - The event to emit
* @private
*/
#emitLayerStatusUpdated(event: LayerStatusUpdatedEvent): void {
// Emit the layersetupdated event
EventHelper.emitEvent(this, this.#onLayerStatusUpdatedHandlers, event);
}

/**
* Registers a callback to be executed whenever the layer status is updated.
* @param {LayerStatusUpdatedDelegate} callback - The callback function
*/
onLayerStatusUpdated(callback: LayerStatusUpdatedDelegate): void {
// Register the layersetupdated event callback
EventHelper.onEvent(this.#onLayerStatusUpdatedHandlers, callback);
}

/**
* Unregisters a callback from being called whenever the layer status is updated.
* @param {LayerStatusUpdatedDelegate} callback - The callback function to unregister
*/
offLayerStatusUpdated(callback: LayerStatusUpdatedDelegate): void {
// Unregister the layersetupdated event callback
EventHelper.offEvent(this.#onLayerStatusUpdatedHandlers, callback);
}
}

// TODO: Rename this type to something like 'store-container-type' as it is now mostly used to indicate in which store to propagate the result set
Expand All @@ -542,3 +576,15 @@ export type LayerSetUpdatedEvent = {
layerPath: string;
resultSet: TypeResultSet;
};

/**
* Define a delegate for the event handler function signature
*/
type LayerStatusUpdatedDelegate = EventDelegateBase<AbstractLayerSet, LayerStatusUpdatedEvent, void>;

/**
* Define an event for the delegate
*/
export type LayerStatusUpdatedEvent = {
layer: ConfigBaseClass;
};
10 changes: 4 additions & 6 deletions packages/geoview-core/src/geo/map/map-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,10 @@ export class MapViewer {
this.#mapInit = true;
this.#emitMapInit();

MapEventProcessor.resetBasemap(this.mapId)
.then()
.catch((error) => {
// Log
logger.logPromiseFailed(' MapEventProcessor.resetBasemap in map-viewer', error);
});
MapEventProcessor.resetBasemap(this.mapId).catch((error) => {
// Log
logger.logPromiseFailed(' MapEventProcessor.resetBasemap in map-viewer', error);
});

// Start checking for when the map will be ready
this.#checkMapReady();
Expand Down
Loading