Skip to content

Commit

Permalink
Fixing bug with 'Private property not on object' which was causing ma…
Browse files Browse the repository at this point in the history
…ny issues including one when removing a layer such as (9d96e8c9-22fe-4ad2-b5e8-94a6991b744b), fixing issue #2643.

Fixing an issue where, when removing layers, the layer configs would be removed from layer registration, but not the actual layer objects
Added support for EPSG:42101 projection, fixing issue #2645
  • Loading branch information
Alex-NRCan committed Jan 10, 2025
1 parent d548365 commit 1722cb0
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 180 deletions.
305 changes: 157 additions & 148 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export function AddNewLayer(): JSX.Element {
geoviewLayerConfig: wmsGeoviewLayerConfig,
layerId: childLayer.Name as string,
layerName: childLayer.Title as string,
} as OgcWmsLayerEntryConfig)
} as unknown as OgcWmsLayerEntryConfig)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,28 @@ export abstract class ConfigBaseClass {
} as unknown as TypeJsonObject;
}

/**
* Clones the configuration class.
*
* @returns {ConfigBaseClass} The cloned ConfigBaseClass object.
*/
clone(): ConfigBaseClass {
// Redirect to clone the object and return it
return this.onClone();
}

/**
* Overridable function to clone a child of a ConfigBaseClass.
*
* @returns {ConfigBaseClass} The cloned child object of a ConfigBaseClass.
*/
protected onClone(): ConfigBaseClass {
// Crash on purpose.
// GV Make sure to implement a 'protected override onClone(): ConfigBaseClass' in the child-class to
// GV use this cloning feature. See OgcWMSLayerEntryConfig for example.
throw new Error(`Not implemented exception onClone on layer path ${this.layerPath}`);
}

/**
* Recursively checks the list of layer entries to see if all of them are greater than or equal to the provided layer status.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { CONST_LAYER_ENTRY_TYPES, TypeSourceImageWmsInitialConfig } from '@/geo/map/map-schema-types';
import { ConfigBaseClass } from '@/core/utils/config/validation-classes/config-base-class';
import { AbstractBaseLayerEntryConfig } from '@/core/utils/config/validation-classes/abstract-base-layer-entry-config';

/** ******************************************************************************************************************************
Expand Down Expand Up @@ -40,4 +41,13 @@ export class OgcWmsLayerEntryConfig extends AbstractBaseLayerEntryConfig {
// Default value for layerConfig.source.serverType is 'mapserver'.
if (!this.source.serverType) this.source.serverType = 'mapserver';
}

/**
* Clones an instance of a OgcWmsLayerEntryConfig.
*
* @returns {ConfigBaseClass} The cloned OgcWmsLayerEntryConfig instance
*/
protected override onClone(): ConfigBaseClass {
return new OgcWmsLayerEntryConfig(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ export function commonValidateListOfLayerEntryConfig(

// TODO: Refactor: Do not do this on the fly here anymore with the new configs (quite unpredictable)...
// Don't forget to replace the old version in the registered layers
MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(groupLayerConfig);
// TODO: Officially remove setLayerEntryConfigObsolete once passed testing
// MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(groupLayerConfig);

(layer.metadata!.layers[esriIndex].subLayerIds as TypeJsonArray).forEach((layerId) => {
// Make sure to copy the layerConfig source before recycling it in the constructors. This was causing the 'source' value to leak between layer entry configs
Expand All @@ -164,7 +165,8 @@ export function commonValidateListOfLayerEntryConfig(

// FIXME: Temporary patch to keep the behavior until those layer classes don't exist
// TODO: Refactor: Do not do this on the fly here anymore with the new configs (quite unpredictable)... (standardizing this call with the other one above for now)
MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(subLayerEntryConfig);
// TODO: Officially remove setLayerEntryConfigObsolete once passed testing
// MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(subLayerEntryConfig);
});

layer.validateListOfLayerEntryConfig(newListOfLayerEntryConfig);
Expand Down
19 changes: 9 additions & 10 deletions packages/geoview-core/src/geo/layer/geoview-layers/raster/wms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import { Options as SourceOptions } from 'ol/source/ImageWMS';
import WMSCapabilities from 'ol/format/WMSCapabilities';
import { Extent } from 'ol/extent';

import cloneDeep from 'lodash/cloneDeep';

import { Cast, TypeJsonArray, TypeJsonObject } from '@/core/types/global-types';
import { TypeJsonArray, TypeJsonObject } from '@/core/types/global-types';
import { AbstractGeoViewLayer, CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { AbstractGeoViewRaster } from '@/geo/layer/geoview-layers/raster/abstract-geoview-raster';
import { TypeLayerEntryConfig, TypeGeoviewLayerConfig, CONST_LAYER_ENTRY_TYPES, layerEntryIsGroupLayer } from '@/geo/map/map-schema-types';
Expand All @@ -21,6 +19,7 @@ import { logger } from '@/core/utils/logger';
import { OgcWmsLayerEntryConfig } from '@/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config';
import { AbstractBaseLayerEntryConfig } from '@/core/utils/config/validation-classes/abstract-base-layer-entry-config';
import { GroupLayerEntryConfig } from '@/core/utils/config/validation-classes/group-layer-entry-config';
import { ConfigBaseClass } from '@/core/utils/config/validation-classes/config-base-class';

export interface TypeWMSLayerConfig extends Omit<TypeGeoviewLayerConfig, 'listOfLayerEntryConfig'> {
geoviewLayerType: typeof CONST_LAYER_TYPES.WMS;
Expand Down Expand Up @@ -396,7 +395,7 @@ export class WMS extends AbstractGeoViewRaster {
}

if ('Layer' in layerFound) {
this.#createGroupLayer(layerFound, layerConfig as AbstractBaseLayerEntryConfig);
this.#createGroupLayer(layerFound, layerConfig as unknown as GroupLayerEntryConfig);
return;
}

Expand All @@ -409,11 +408,11 @@ export class WMS extends AbstractGeoViewRaster {
* This method create recursively dynamic group layers from the service metadata.
*
* @param {TypeJsonObject} layer The dynamic group layer metadata.
* @param {AbstractBaseLayerEntryConfig} layerConfig The layer configurstion associated to the dynamic group.
* @param {GroupLayerEntryConfig} layerConfig The group layer configuration associated to the dynamic group.
* @private
*/
// GV Layers Refactoring - Obsolete (in config)
#createGroupLayer(layer: TypeJsonObject, layerConfig: AbstractBaseLayerEntryConfig): void {
#createGroupLayer(layer: TypeJsonObject, layerConfig: GroupLayerEntryConfig): void {
// TODO: Refactor - createGroup is the same thing for all the layers type? group is a geoview structure.
// TO.DOCONT: Should it be handle upper in abstract class to loop in structure and launch the creation of a leaf?
// TODO: The answer is no. Even if the final structure is the same, the input structure is different for each geoview layer types.
Expand All @@ -423,17 +422,17 @@ export class WMS extends AbstractGeoViewRaster {
arrayOfLayerMetadata.forEach((subLayer) => {
// Log for pertinent debugging purposes
logger.logTraceCore('WMS - createGroupLayer', 'Cloning the layer config', layerConfig.layerPath);
const subLayerEntryConfig: TypeLayerEntryConfig = cloneDeep(layerConfig);
subLayerEntryConfig.parentLayerConfig = Cast<GroupLayerEntryConfig>(layerConfig);
const subLayerEntryConfig: ConfigBaseClass = layerConfig.clone();
subLayerEntryConfig.parentLayerConfig = layerConfig;
subLayerEntryConfig.layerId = subLayer.Name as string;
subLayerEntryConfig.layerName = subLayer.Title as string;
newListOfLayerEntryConfig.push(subLayerEntryConfig);
newListOfLayerEntryConfig.push(subLayerEntryConfig as TypeLayerEntryConfig);

// FIXME: Temporary patch to keep the behavior until those layer classes don't exist
this.getMapViewer().layer.registerLayerConfigInit(subLayerEntryConfig);
});

const switchToGroupLayer = Cast<GroupLayerEntryConfig>(layerConfig);
const switchToGroupLayer = layerConfig;
switchToGroupLayer.entryType = CONST_LAYER_ENTRY_TYPES.GROUP;
switchToGroupLayer.layerName = layer.Title as string;
switchToGroupLayer.isMetadataLayerGroup = true;
Expand Down
46 changes: 27 additions & 19 deletions packages/geoview-core/src/geo/layer/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,22 +250,23 @@ export class LayerApi {
return this.#layerEntryConfigs?.[layerPath];
}

/**
* Obsolete function to set the layer configuration in the registered layers.
*/
setLayerEntryConfigObsolete(layerConfig: ConfigBaseClass): void {
// FIXME: This function should be deleted once the Layers refactoring is done. It unregisters and registers an updated layer entry config.
// FIX.MECONT: This is because of the EsriDynamic and EsriFeature entry config being generated on-the-fly when registration of layer entry config has already happened.
// Get the config already existing if any
const alreadyExisting = this.#layerEntryConfigs[layerConfig.layerPath];
if (alreadyExisting) {
// Unregister the old one
this.unregisterLayerConfig(alreadyExisting, false);
}

// Register this new one
this.registerLayerConfigInit(layerConfig);
}
// TODO: Officially remove setLayerEntryConfigObsolete once passed testing
// /**
// * Obsolete function to set the layer configuration in the registered layers.
// */
// setLayerEntryConfigObsolete(layerConfig: ConfigBaseClass): void {
// // FIXME: This function should be deleted once the Layers refactoring is done. It unregisters and registers an updated layer entry config.
// // FIX.MECONT: This is because of the EsriDynamic and EsriFeature entry config being generated on-the-fly when registration of layer entry config has already happened.
// // Get the config already existing if any
// const alreadyExisting = this.#layerEntryConfigs[layerConfig.layerPath];
// if (alreadyExisting) {
// // Unregister the old one
// this.unregisterLayerConfig(alreadyExisting, false);
// }

// // Register this new one
// this.registerLayerConfigInit(layerConfig);
// }

/**
* Returns the OpenLayer instance associated with the layer path.
Expand Down Expand Up @@ -1202,12 +1203,19 @@ export class LayerApi {
// Remove layer info from registered layers
this.getLayerEntryConfigIds().forEach((registeredLayerPath) => {
if (registeredLayerPath.startsWith(layerPath)) {
// Remove ol layer
// Remove actual OL layer from the map
if (this.getOLLayer(registeredLayerPath)) this.mapViewer.map.removeLayer(this.getOLLayer(registeredLayerPath) as BaseLayer);
// Unregister layer

// Unregister layer config from the application
this.unregisterLayerConfig(this.getLayerEntryConfig(registeredLayerPath)!);
// Remove from registered layers

// Remove from registered layer configs
delete this.#layerEntryConfigs[registeredLayerPath];
delete this.#geoviewLayers[registeredLayerPath];

// Remove from registered layers
delete this.#gvLayers[registeredLayerPath];
delete this.#olLayers[registeredLayerPath];
}
});

Expand Down
17 changes: 17 additions & 0 deletions packages/geoview-core/src/geo/utils/projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export abstract class Projection {
3578: 'EPSG:3578',
LCC: 'EPSG:3978',
3979: 'EPSG:3979',
42101: 'EPSG:42101',
102100: 'EPSG:102100', // TODO: Minor - The official name of this projection is ESRI:102100 (not EPSG:102100). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
102184: 'EPSG:102184', // TODO: Minor - The official name of this projection is ESRI:102184 (not EPSG:102184). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
102190: 'EPSG:102190', // TODO: Minor - The official name of this projection is ESRI:102190 (not EPSG:102190). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
Expand Down Expand Up @@ -414,6 +415,21 @@ function init4269Projection(): void {
if (projection) Projection.PROJECTIONS['4269'] = projection;
}

/**
* Initializes the EPSG:42101 projection
*/
function init42101Projection(): void {
proj4.defs(
Projection.PROJECTION_NAMES[42101],
'+proj=lcc +lat_0=0 +lon_0=-95 +lat_1=49 +lat_2=77 +x_0=0 +y_0=-8000000 +datum=WGS84 +units=m +no_defs +type=crs'
);
register(proj4);

const projection = olGetProjection(Projection.PROJECTION_NAMES[42101]);

if (projection) Projection.PROJECTIONS['42101'] = projection;
}

/**
* Initializes the EPSG:3979 projection
*/
Expand Down Expand Up @@ -499,6 +515,7 @@ initCSRS98Projection();
init3578Projection();
init3979Projection();
init4269Projection();
init42101Projection();
init102100Projection();
init102184Projection();
init102190Projection();
Expand Down

0 comments on commit 1722cb0

Please sign in to comment.