Skip to content

Commit

Permalink
2471-Comple_layer_tree_coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
ychoquet committed Sep 12, 2024
1 parent 143e514 commit 014ea2e
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 116 deletions.
72 changes: 51 additions & 21 deletions packages/geoview-core/public/templates/config-sandbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ <h1><strong>Sandbox Configuration</strong></h1>
<option value="esriFeature">EsriFeature</option>
<option value="geoCore">GeoCore</option>
<option value="ogcWms">WMS</option>
<option value="esriImage">EsriImage</option>
<option value="GeoJSON">GeoJSON</option>
</select>
</div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;URL:&nbsp;
Expand Down Expand Up @@ -318,11 +320,20 @@ <h1><strong>Sandbox Configuration</strong></h1>
<input type="checkbox" id="sampleUrlTab4" name="sampleUrlTab4">
</form>
GeoView Layer Type:
<select id="geoviewLayerTypeTab4">
<select id="geoviewLayerTypeTab4">
<option value="unknown">unknown</option>
<option value="esriDynamic">EsriDynamic</option>
<option value="esriFeature">EsriFeature</option>
<option value="ogcWms">WMS</option>
<option value="ogcWfs">WFS</option>
<option value="esriImage">EsriImage</option>
<option value="GeoJSON">GeoJSON</option>
<option value="CSV">CSV</option>
<option value="ogcFeature">Ogc Feature</option>
<option value="GeoPackage">GeoPackage</option>
<option value="xyzTiles">xyz Tiles</option>
<option value="vectorTiles">Vector Tiles</option>
<option value="imageStatic">Image Static</option>
</select>
</div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;URL:&nbsp;
Expand Down Expand Up @@ -446,7 +457,7 @@ <h4 id="HLCONF1">Sanbox Map</h4>
generateLayerPathErrorFlag = (listOfLayerEntryConfig, buffer = '', prefix = '') => {
listOfLayerEntryConfig.forEach((layer) => {
buffer = buffer ? `${buffer}\n` : '';
buffer = `${buffer}${layer.getLayerPath()}: ${layer.getErrorDetectedFlag() ? 'ERROR' : 'Ok'}`;
buffer = `${buffer}${layer?.getLayerPath?.() || layer.layerName}: ${layer?.getErrorDetectedFlag?.() ? 'ERROR' : 'Ok'}`;
if (layer.isLayerGroup) buffer = generateLayerPathErrorFlag(layer.listOfLayerEntryConfig, buffer, prefix ? `${prefix}.${layer.layerId}` : layer.layerId);
});
return buffer;
Expand Down Expand Up @@ -656,6 +667,8 @@ <h4 id="HLCONF1">Sanbox Map</h4>
esriDynamic: 'https://maps-cartes.ec.gc.ca/arcgis/rest/services/CESI/MapServer/',
esriFeature: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/Temporal_Test_Bed_en/MapServer/',
ogcWms: 'https://geo.weather.gc.ca/geomet',
esriImage: 'NOT IMPLEMENTED', // 'https://www5.agr.gc.ca/atlas/rest/services/imageservices/annual_crop_inventory_2022/ImageServer',
GeoJSON: 'NOT IMPLEMENTED', // 'https://canadian-geospatial-platform.github.io/geoview/public/datasets/geojson/metadata.json',
};

// Get the GeoView Layer Type drop-down object used to select the type of layer.
Expand Down Expand Up @@ -685,8 +698,8 @@ <h4 id="HLCONF1">Sanbox Map</h4>
// Type drop-down with the resulting value.
serviceUrlAreaTab2.addEventListener('keyup', (e) => {
if (sampleUrlTab2.checked) return;
GeoviewLayerTypeDropDownTab2.value = cgpv.api.config.guessLayerType(serviceUrlAreaTab2.value);
if (!GeoviewLayerTypeDropDownTab2.value) GeoviewLayerTypeDropDownTab2.value = 'unknown';
const value = cgpv.api.config.guessLayerType(serviceUrlAreaTab2.value);
GeoviewLayerTypeDropDownTab2.value = value || 'unknown';
});

// Initialise the GeoView Layer Type drop-down value and set input field accordingly
Expand Down Expand Up @@ -843,6 +856,15 @@ <h4 id="HLCONF1">Sanbox Map</h4>
esriDynamic: 'https://maps-cartes.ec.gc.ca/arcgis/rest/services/CESI/MapServer/',
esriFeature: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/Temporal_Test_Bed_en/MapServer/',
ogcWms: 'https://geo.weather.gc.ca/geomet',
esriImage: 'https://www5.agr.gc.ca/atlas/rest/services/imageservices/annual_crop_inventory_2022/ImageServer',
GeoJSON: 'https://canadian-geospatial-platform.github.io/geoview/public/datasets/geojson/metadata.json',
CSV: 'https://canadian-geospatial-platform.github.io/geoview/public/datasets/csv-files/Station_List_Minus_HQ-MELCC.csv',
ogcFeature: 'https://b6ryuvakk5.execute-api.us-east-1.amazonaws.com/dev/collections',
GeoPackage: 'https://canadian-geospatial-platform.github.io/geoview/public/datasets/geopackages/rivers.gpkg',
ogcWfs: 'https://ahocevar.com/geoserver/wfs?REQUEST=GetCapabilities&VERSION=2.0.0&SERVICE=WFS',
xyzTiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
vectorTiles: 'https://tiles.arcgis.com/tiles/HsjBaDykC1mjhXz9/arcgis/rest/services/CBMT3978_v11/VectorTileServer/tile/{z}/{y}/{x}.pbf',
imageStatic: 'https://datacube-prod-data-public.s3.ca-central-1.amazonaws.com/store/imagery/aerial/napl/napl-ring-of-fire/napl-ring-of-fire-1954-08-07-60k-thumbnail.png',
};

// Get the GeoView Layer Type drop-down object used to select the type of layer.
Expand Down Expand Up @@ -905,23 +927,31 @@ <h4 id="HLCONF1">Sanbox Map</h4>
return item.trim();
}) : [];

// Call the ConfigApi to get the Layer Tree
const metadataLayerTree = await cgpv.api.config.createMetadataLayerTree(
serviceUrlAreaTab4.value.trim(),
layerTypeTab4,
layerListTab4,
languageTab4
);
// Output instanciation result
metadataLayerTreeString = `${JSON.stringify(metadataLayerTree, (key, value) => {
if (['', 'layerId', 'layerName', 'isLayerGroup', 'listOfLayerEntryConfig'].includes(key)) return value;
if (/^\d+$/.test(key)) return value;
return undefined;
}, 2)}\n`;
layerPathErrorFlag = generateLayerPathErrorFlag(metadataLayerTree);

if (metadataLayerTree) printMessage(messageTab4, 'Layer tree is valid');
else printMessage(messageTab4, 'Cannot generate layer tree, see console for details...', 'error');
try {
// Call the ConfigApi to get the Layer Tree
const metadataLayerTree = await cgpv.api.config.createMetadataLayerTree(
serviceUrlAreaTab4.value.trim(),
layerTypeTab4,
layerListTab4,
languageTab4
);

// Output instanciation result
metadataLayerTreeString = `${JSON.stringify(metadataLayerTree, (key, value) => {
// Only display essential information
if (['', 'layerId', 'layerName', 'isLayerGroup', 'listOfLayerEntryConfig'].includes(key)) return value;
if (/^\d+$/.test(key)) return value;
return undefined;
}, 2)}\n`;
layerPathErrorFlag = generateLayerPathErrorFlag(metadataLayerTree);

printMessage(messageTab4, 'Layer tree is valid');
} catch (error) {
metadataLayerTreeString = '';
layerPathErrorFlag = '[]';
printMessage(messageTab4, 'Cannot generate layer tree, see console for details...', 'error');
cgpv.logger.logError('Cannot generate layer tree, see console for details\n', error);
}

elementSelectorTab4.dispatchEvent(new Event('change'));
});
Expand Down
125 changes: 121 additions & 4 deletions packages/geoview-core/src/api/config/config-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cloneDeep from 'lodash/cloneDeep';
import mergeWith from 'lodash/mergeWith';

import { CV_DEFAULT_MAP_FEATURE_CONFIG, CV_CONFIG_GEOCORE_TYPE, CV_CONST_LAYER_TYPES } from '@config/types/config-constants';
import { TypeJsonValue, TypeJsonObject, toJsonObject, TypeJsonArray, Cast } from '@config/types/config-types';
Expand All @@ -12,7 +13,15 @@ import {
} from '@config/types/map-schema-types';
import { MapConfigError } from '@config/types/classes/config-exceptions';

import { generateId, isJsonString, removeCommentsFromJSON } from '@/core/utils/utilities';
import {
createLocalizedString,
findPropertyNameByRegex,
generateId,
getXMLHttpRequest,
isJsonString,
removeCommentsFromJSON,
xmlToJson,
} from '@/core/utils/utilities';
import { logger } from '@/core//utils/logger';

/**
Expand Down Expand Up @@ -486,7 +495,7 @@ export class ConfigApi {
geoviewLayerId: generateId(),
geoviewLayerName: { en: 'unknown', fr: 'inconnu' },
geoviewLayerType: layerType,
metadataAccessPath: { en: serviceAccessString, fr: serviceAccessString },
metadataAccessPath: createLocalizedString(serviceAccessString),
listOfLayerEntryConfig: listOfLayerId.map((layerId) => {
return { layerId };
}),
Expand Down Expand Up @@ -515,10 +524,118 @@ export class ConfigApi {
listOfLayerId: TypeJsonArray = [],
language: TypeDisplayLanguage = 'en'
): Promise<EntryConfigBaseClass[]> {
const geoviewLayerConfig = await ConfigApi.createLayerConfig(serviceAccessString, layerType, listOfLayerId, language);
// GV: TEMPORARY SECTION TO BE DELETED WHEN ALL LAYER TYPES ARE IMPLEMENTED
// GV: THE CODE IN THIS SECTION IS NOT PERMANANT BECAUSE THE CORRESPONDING
// GV: GEOVIEW LAYER CLASSES HAVE NOT YET BEEN IMPLEMENTED.
// GV: BEGINNING OF TEMPORARY SECTION
async function fetchJsonMetadata(url: string): Promise<TypeJsonObject> {
const response = await fetch(`${url}?f=json`);
return response.json();
}

async function fetchXmlMetadata(url: string): Promise<TypeJsonObject> {
let metadataUrl = url;
// check if url contains metadata parameters for the getCapabilities request and reformat the urls
const getCapabilitiesUrl =
metadataUrl!.indexOf('?') > -1 ? metadataUrl.substring(metadataUrl!.indexOf('?')) : `?service=WFS&request=GetCapabilities`;
metadataUrl = metadataUrl!.indexOf('?') > -1 ? metadataUrl.substring(0, metadataUrl!.indexOf('?')) : metadataUrl;
if (metadataUrl) {
const metadataString = await getXMLHttpRequest(`${metadataUrl}${getCapabilitiesUrl}`);
if (metadataString === '{}') throw new MapConfigError('Unable to build metadata layer tree (empty metadata).');
else {
// need to pass a xmldom to xmlToJson
const xmlDOMCapabilities = new DOMParser().parseFromString(metadataString, 'text/xml');
const xmlJsonCapabilities = xmlToJson(xmlDOMCapabilities);
const capabilitiesObject = findPropertyNameByRegex(xmlJsonCapabilities, /(?:WFS_Capabilities)/);
return capabilitiesObject as TypeJsonObject;
}
} else throw new MapConfigError('Unable to build metadata layer tree (empty metadata url).');
}

let jsonData: TypeJsonObject;
switch (layerType) {
case 'ogcWfs':
jsonData = (await fetchXmlMetadata(serviceAccessString))?.FeatureTypeList?.FeatureType;
if (Array.isArray(jsonData))
return (jsonData as TypeJsonArray).map((layer) => {
return Cast<EntryConfigBaseClass>({
layerId: layer.Name['#text'],
layerName: layer.Title['#text'],
});
});
return [];
break;
case 'ogcFeature':
jsonData = await fetchJsonMetadata(serviceAccessString);
if (jsonData.collections)
return (jsonData.collections as TypeJsonArray).map((layer) => {
return Cast<EntryConfigBaseClass>({
layerId: layer.id,
layerName: layer.title,
});
});
if (jsonData.id)
return [
Cast<EntryConfigBaseClass>({
layerId: jsonData.id,
layerName: jsonData.title,
}),
];
return [];
break;
case 'esriImage':
jsonData = await fetchJsonMetadata(serviceAccessString);
if (jsonData.name)
return [
Cast<EntryConfigBaseClass>({
layerId: jsonData.name,
layerName: jsonData.name,
}),
];
return [];
break;
case 'GeoJSON':
if (
serviceAccessString.toLowerCase().split('?')[0].endsWith('.json') ||
serviceAccessString.toLowerCase().split('?')[0].endsWith('.geojson')
) {
jsonData = await fetchJsonMetadata(serviceAccessString.split('?')[0]);
jsonData = mergeWith(jsonData, cloneDeep(jsonData), (property, sourceValue) => {
if (property.en || property.fr) return sourceValue[language] || sourceValue.en || sourceValue.fr;
return undefined;
});
return Cast<EntryConfigBaseClass[]>(jsonData.listOfLayerEntryConfig);
}
return [];
break;
case 'CSV':
case 'xyzTiles':
case 'imageStatic':
case 'vectorTiles':
case 'GeoPackage':
return [];
break;
default:
break;
}

// GV: END OF TEMPORARY SECTION

const geoviewLayerConfig = await ConfigApi.createLayerConfig(serviceAccessString, layerType, [], language);

if (geoviewLayerConfig && !geoviewLayerConfig.getErrorDetectedFlag()) {
// set layer tree creation filter (only the layerIds specified will be retained).
// If an empty Array [] is used, the layer tree will be built using the service metadata.
geoviewLayerConfig.setMetadataLayerTree(
Cast<EntryConfigBaseClass[]>(
listOfLayerId.map((layerId) => {
return { layerId };
})
)
);

await geoviewLayerConfig.fetchServiceMetadata();
if (!geoviewLayerConfig.getErrorDetectedFlag()) return geoviewLayerConfig.getMetadataLayerTree();
if (!geoviewLayerConfig.getErrorDetectedFlag()) return geoviewLayerConfig.getMetadataLayerTree()!;
}
throw new MapConfigError('Unable to build metadata layer tree.');
}
Expand Down
Loading

0 comments on commit 014ea2e

Please sign in to comment.