Skip to content

Commit

Permalink
Partial - GeoCore config testing
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewMuehlhauserNRCan committed Jan 13, 2025
1 parent 462e3b4 commit 11cea28
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,13 @@ export abstract class AbstractGeoViewLayer {
}, 0);
}

/**
* Method for pre-emptively getting the full config for applying entry configs
*/
async preflightGetAllLayerEntryConfigs(): Promise<void> {
await this.getAdditionalServiceDefinition();
}

/** ***************************************************************************************************************************
* This method is used to create the layers specified in the listOfLayerEntryConfig attribute inherited from its parent.
* Normally, it is the second method called in the life cycle of a GeoView layer, the first one being the constructor.
Expand Down
201 changes: 169 additions & 32 deletions packages/geoview-core/src/geo/layer/other/geocore.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import { GroupLayerEntryConfig, TypeDisplayLanguage } from '@config/types/map-schema-types';
import { GroupLayerEntryConfig, TypeDisplayLanguage, TypeGeoviewLayerType } from '@config/types/map-schema-types';

import { UUIDmapConfigReader } from '@/core/utils/config/reader/uuid-config-reader';
// import { UUIDmapConfigReader } from '@/api/config/uuid-config-reader';
import { ConfigValidation } from '@/core/utils/config/config-validation';
import { GeochartEventProcessor } from '@/api/event-processors/event-processor-children/geochart-event-processor';
import { logger } from '@/core/utils/logger';
import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor';

import { GeoCoreLayerConfig, TypeGeoviewLayerConfig, TypeLayerEntryConfig } from '@/geo/map/map-schema-types';
import { GeoJSON, layerConfigIsGeoJSON } from '@/geo/layer/geoview-layers/vector/geojson';
import { GeoPackage, layerConfigIsGeoPackage } from '@/geo/layer/geoview-layers/vector/geopackage';
import { layerConfigIsWMS, WMS } from '@/geo/layer/geoview-layers/raster/wms';
import { EsriDynamic, layerConfigIsEsriDynamic } from '@/geo/layer/geoview-layers/raster/esri-dynamic';
import { EsriFeature, layerConfigIsEsriFeature } from '@/geo/layer/geoview-layers/vector/esri-feature';
import { EsriImage, layerConfigIsEsriImage } from '@/geo/layer/geoview-layers/raster/esri-image';
import { ImageStatic, layerConfigIsImageStatic } from '@/geo/layer/geoview-layers/raster/image-static';
import { layerConfigIsWFS, WFS } from '@/geo/layer/geoview-layers/vector/wfs';
import { layerConfigIsOgcFeature, OgcFeature } from '@/geo/layer/geoview-layers/vector/ogc-feature';
import { layerConfigIsXYZTiles, XYZTiles } from '@/geo/layer/geoview-layers/raster/xyz-tiles';
import { layerConfigIsVectorTiles, VectorTiles } from '@/geo/layer/geoview-layers/raster/vector-tiles';
import { CSV, layerConfigIsCSV } from '@/geo/layer/geoview-layers/vector/csv';
import { TypeJsonValue } from '@/core/types/global-types';
import { api } from '@/app';
import { AbstractGeoViewLayer, api } from '@/app';

/**
* Class used to add geoCore layer to the map
Expand All @@ -30,6 +43,111 @@ export class GeoCore {
this.#displayLanguage = displayLanguage;
}

/**
* Get full configuration of layer
* @param {TypeGeoviewLayerConfig} layerConfig The layer config from the geocore response
* @returns {TypeGeoviewLayerConfig} The complete layerConfig
*/
async getFullConfig(layerConfig: TypeGeoviewLayerConfig): Promise<TypeGeoviewLayerConfig> {
let layerBeingAdded: AbstractGeoViewLayer;
let layerType: TypeGeoviewLayerType;
if (layerConfigIsGeoJSON(layerConfig)) {
layerType = 'GeoJSON';
layerBeingAdded = new GeoJSON(this.#mapId, layerConfig);
} else if (layerConfigIsGeoPackage(layerConfig)) {
layerType = 'GeoPackage';
layerBeingAdded = new GeoPackage(this.#mapId, layerConfig);
} else if (layerConfigIsCSV(layerConfig)) {
layerType = 'CSV';
layerBeingAdded = new CSV(this.#mapId, layerConfig);
} else if (layerConfigIsWMS(layerConfig)) {
layerType = 'ogcWms';
layerBeingAdded = new WMS(this.#mapId, layerConfig);
} else if (layerConfigIsEsriDynamic(layerConfig)) {
layerType = 'esriDynamic';
layerBeingAdded = new EsriDynamic(this.#mapId, layerConfig);
} else if (layerConfigIsEsriFeature(layerConfig)) {
layerType = 'esriFeature';
layerBeingAdded = new EsriFeature(this.#mapId, layerConfig);
} else if (layerConfigIsEsriImage(layerConfig)) {
layerType = 'esriImage';
layerBeingAdded = new EsriImage(this.#mapId, layerConfig);
} else if (layerConfigIsImageStatic(layerConfig)) {
layerType = 'imageStatic';
layerBeingAdded = new ImageStatic(this.#mapId, layerConfig);
} else if (layerConfigIsWFS(layerConfig)) {
layerType = 'ogcWfs';
layerBeingAdded = new WFS(this.#mapId, layerConfig);
} else if (layerConfigIsOgcFeature(layerConfig)) {
layerType = 'ogcFeature';
layerBeingAdded = new OgcFeature(this.#mapId, layerConfig);
} else if (layerConfigIsXYZTiles(layerConfig)) {
layerType = 'xyzTiles';
layerBeingAdded = new XYZTiles(this.#mapId, layerConfig);
} else if (layerConfigIsVectorTiles(layerConfig)) {
layerType = 'vectorTiles';
layerBeingAdded = new VectorTiles(this.#mapId, layerConfig);
} else {
// TODO: Refactor - Throw an Error when falling in this else and change return type to AbstractGeoViewLayer without undefined
throw new Error(`Layer type ${layerConfig.geoviewLayerType} not supported`);
}
await layerBeingAdded?.preflightGetAllLayerEntryConfigs();
const newConfig: TypeGeoviewLayerConfig = {
...layerBeingAdded,
geoviewLayerType: layerType,
};

return newConfig;
}

static cloneLayerEntryConfigs(entries: TypeLayerEntryConfig[]): TypeLayerEntryConfig[] {
return entries.map((entry) => {
// Create new object with preserved getters/setters
const clonedEntry = Object.create(Object.getPrototypeOf(entry), Object.getOwnPropertyDescriptors(entry));

// If this entry has its own listOfLayerEntryConfig
if (clonedEntry.listOfLayerEntryConfig) {
clonedEntry.listOfLayerEntryConfig = GeoCore.cloneLayerEntryConfigs(clonedEntry.listOfLayerEntryConfig);
}

return clonedEntry;
});
}

static subMergeLayerEntryConfigs(
layerEntryConfigs: TypeLayerEntryConfig[],
configMap: Map<string, GroupLayerEntryConfig | TypeLayerEntryConfig>
): TypeLayerEntryConfig[] {
return layerEntryConfigs.map((layerEntryConfig) => {
const newConfig = configMap.get(layerEntryConfig.layerId);
if (!newConfig) {
// If no new config to merge, just clone the existing one
return Object.create(Object.getPrototypeOf(layerEntryConfig), Object.getOwnPropertyDescriptors(layerEntryConfig));
}

// Create base merged config preserving getters/setters
const mergedConfig = Object.create(Object.getPrototypeOf(layerEntryConfig), Object.getOwnPropertyDescriptors(layerEntryConfig));

if (mergedConfig.listOfLayerEntryConfig) {
mergedConfig.listOfLayerEntryConfig = GeoCore.subMergeLayerEntryConfigs(mergedConfig.listOfLayerEntryConfig, configMap);
}

// Merge initial Settings
if (newConfig.initialSettings) {
mergedConfig.initialSettings = {
...layerEntryConfig.initialSettings,
...newConfig.initialSettings,
// Special handling for states
states: {
...layerEntryConfig.initialSettings?.states,
...newConfig.initialSettings?.states,
},
};
}
return mergedConfig;
});
}

/**
* Merges two listOfLayerEntryConfigs together.
* Properties from the second will overwrite the first
Expand All @@ -47,15 +165,18 @@ export class GeoCore {

// Get a map of the configs for the new LayerEntryConfigs based on the Layer IDs
const mergedLayerEntryConfig = { ...geocoreLayerEntryConfig };
mergedLayerEntryConfig.listOfLayerEntryConfig = GeoCore.cloneLayerEntryConfigs(mergedLayerEntryConfig.listOfLayerEntryConfig);
const newConfigMap = new Map<string, GroupLayerEntryConfig | TypeLayerEntryConfig>();

function addToConfigMap(entryConfigs: TypeLayerEntryConfig[]): void {
entryConfigs.forEach((entryConfig) => {
// Forces the keyId to be string, can change to integer otherwise
const keyId = `${entryConfig.layerId}`;
if (entryConfig.listOfLayerEntryConfig) {
newConfigMap.set(entryConfig.layerId, entryConfig);
newConfigMap.set(keyId, entryConfig);
addToConfigMap(entryConfig.listOfLayerEntryConfig);
} else {
newConfigMap.set(entryConfig.layerId, entryConfig);
newConfigMap.set(keyId, entryConfig);
}
});
}
Expand All @@ -69,13 +190,18 @@ export class GeoCore {
// Go through all layers and group layers backwards and remove layers as necessary.
// Use backwards so that the indexing isn't messed up when moving children up to the parent level
for (let i = adjustedLayerEntryConfigs.length - 1; i >= 0; i--) {
// remove problomatic properties
adjustedLayerEntryConfigs[i].layerStatus = 'newInstance';

if (adjustedLayerEntryConfigs[i].listOfLayerEntryConfig) {
adjustedLayerEntryConfigs[i].listOfLayerEntryConfig = removeLayerConfigs(
adjustedLayerEntryConfigs[i].listOfLayerEntryConfig as TypeLayerEntryConfig[]
);
}

if (newConfigMap.get(adjustedLayerEntryConfigs[i].layerId)) {
// if the layer is NOT in the configMap
if (!newConfigMap.get(adjustedLayerEntryConfigs[i].layerId)) {
// Move children up before removing the parent
if (adjustedLayerEntryConfigs[i].listOfLayerEntryConfig) {
const numEntries = adjustedLayerEntryConfigs[i].listOfLayerEntryConfig.length;
for (let j = numEntries - 1; j >= 0; j--) {
Expand All @@ -92,28 +218,11 @@ export class GeoCore {
mergedLayerEntryConfig.listOfLayerEntryConfig as TypeLayerEntryConfig[]
);

// TODO! May be an issue. Currently ignoring the listOfLayerEntryConfig order and just keeping layers based on ID ...
// Need to make sure the initialSettings are updated properly and not over-written entirely
function mergeLayerEntryConfigs(
layerEntryConfigs: TypeLayerEntryConfig[],
configMap: Map<string, GroupLayerEntryConfig | TypeLayerEntryConfig>
): TypeLayerEntryConfig[] {
const newLayerEntryConfigs = [...layerEntryConfigs];
newLayerEntryConfigs.forEach((layerEntryConfig) => {
const newConfig = configMap.get(layerEntryConfig.layerId);
if (!newConfig) return;
const mergedConfig = { ...layerEntryConfig, ...newConfig };
if (newConfig.initialSettings) {
mergedConfig.initialSettings = { ...layerEntryConfig.initialSettings, ...newConfig.initialSettings };
mergedConfig.initialSettings.states = { ...layerEntryConfig.initialSettings.states, ...newConfig.initialSettings.states };
}
if (layerEntryConfig.listOfLayerEntryConfig) {
mergedConfig.listOfLayerEntryConfig = mergeLayerEntryConfigs(layerEntryConfig.listOfLayerEntryConfig, configMap);
}
});
return newLayerEntryConfigs;
}
mergedLayerEntryConfig.listOfLayerEntryConfig = mergeLayerEntryConfigs(mergedLayerEntryConfig.listOfLayerEntryConfig, newConfigMap);
mergedLayerEntryConfig.listOfLayerEntryConfig = GeoCore.subMergeLayerEntryConfigs(
mergedLayerEntryConfig.listOfLayerEntryConfig,
newConfigMap
);
mergedLayerEntryConfig.listOfLayerEntryConfig = GeoCore.cloneLayerEntryConfigs(mergedLayerEntryConfig.listOfLayerEntryConfig);
return mergedLayerEntryConfig;
}

Expand Down Expand Up @@ -142,18 +251,46 @@ export class GeoCore {
if (layerConfig?.geoviewLayerName) response.layers[0].listOfLayerEntryConfig[0].layerName = layerConfig.geoviewLayerName;
}

// if (layerConfig?.listOfLayerEntryConfig) {
// response.layers = response.layers.map((responseLayer) => {
// return GeoCore.mergeLayerEntryConfigs(responseLayer, layerConfig);
// });
// }
if (layerConfig?.initialSettings) {
response.layers[0].initialSettings = {
...response.layers[0].initialSettings,
...layerConfig.initialSettings,
// Special handling for states
states: {
...response.layers[0].initialSettings?.states,
...layerConfig.initialSettings?.states,
},
};
}

if (layerConfig?.listOfLayerEntryConfig) {
// const newLayers: Promise<TypeGeoviewLayerConfig | undefined>[] = response.layers.map(async (lyr) => {
// const fullConfig = await this.getFullConfig(lyr);
// if (!fullConfig) return Promise.resolve(undefined);
// return GeoCore.mergeLayerEntryConfigs(fullConfig, layerConfig);
// });

// // Set the response layers to the merged config values
// const resolvedLayers = await Promise.all(newLayers);
// resolvedLayers.forEach((lyr, i) => {
// if (lyr) {
// response.layers[i] = lyr;
// }
// });
response.layers[0].listOfLayerEntryConfig = layerConfig.listOfLayerEntryConfig;
}

// For each found geochart associated with the Geocore UUIDs
response.geocharts?.forEach((geochartConfig) => {
// Add a GeoChart
GeochartEventProcessor.addGeochartChart(this.#mapId, geochartConfig.layers[0].layerId as string, geochartConfig);
});

// Testing only
// response.layers[0].listOfLayerEntryConfig[0].layerId = '1';
// response.layers[0].listOfLayerEntryConfig[0].layerName = 'Name Set from Config';
// response.layers[0].listOfLayerEntryConfig[0].initialSettings.states.visible = false;

return response.layers;
} catch (error) {
// Log
Expand Down

0 comments on commit 11cea28

Please sign in to comment.