UNPKG

@loaders.gl/i3s

Version:
99 lines (98 loc) 3.41 kB
import { JSONLoader, load } from '@loaders.gl/core'; /** * WKID, or Well-Known ID, of the CRS. Specify either WKID or WKT of the CRS. * Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.8/spatialReference.cmn.md */ const SUPPORTED_WKID = 4326; const ARCGIS_SCENE_SERVER_LAYER_TYPE = 'ArcGISSceneServiceLayer'; const BUILDING_SCENE_LAYER = 'BuildingSceneLayer'; const INTEGRATED_MESH_LAYER = 'IntegratedMeshLayer'; const GROUP_LAYER = 'GroupLayer'; /** * Supported layers list * Possible operational layers in WebScene: https://developers.arcgis.com/web-scene-specification/objects/operationalLayers/ */ const SUPPORTED_LAYERS_TYPES = [ ARCGIS_SCENE_SERVER_LAYER_TYPE, INTEGRATED_MESH_LAYER, BUILDING_SCENE_LAYER, GROUP_LAYER ]; const NO_AVAILABLE_SUPPORTED_LAYERS_ERROR = 'NO_AVAILABLE_SUPPORTED_LAYERS_ERROR'; const NOT_SUPPORTED_CRS_ERROR = 'NOT_SUPPORTED_CRS_ERROR'; /** * Provides additional information in the exception Error object, e.g. unsupported layer types. * @param message - message used in the Error object * @param details - additional information that can be used to handle the exception. * @example throw new LayerError(NO_AVAILABLE_SUPPORTED_LAYERS_ERROR, unsupportedLayers); */ export class LayerError extends Error { details; constructor(message, details) { super(message); this.details = details; this.name = 'LayerError'; } } /** * Parses ArcGIS WebScene * @param data */ export async function parseWebscene(data) { const layer0 = JSON.parse(new TextDecoder().decode(data)); const { operationalLayers } = layer0; const { layers, unsupportedLayers } = await parseOperationalLayers(operationalLayers, true); if (!layers.length) { throw new LayerError(NO_AVAILABLE_SUPPORTED_LAYERS_ERROR, unsupportedLayers); } return { header: layer0, layers, unsupportedLayers }; } /** * Recursively parses WebScene operational layers. * @param layersList */ async function parseOperationalLayers(layersList, needToCheckCRS) { const layers = []; let unsupportedLayers = []; for (let index = 0; index < layersList.length; index++) { const layer = layersList[index]; const isLayerSupported = SUPPORTED_LAYERS_TYPES.includes(layer.layerType); if (isLayerSupported) { if (needToCheckCRS && layer.layerType !== GROUP_LAYER) { await checkSupportedIndexCRS(layer); needToCheckCRS = false; } layers.push(layer); } else { unsupportedLayers.push(layer); } if (layer.layers?.length) { const { layers: childLayers, unsupportedLayers: childUnsupportedLayers } = await parseOperationalLayers(layer.layers, needToCheckCRS); layer.layers = childLayers; unsupportedLayers = [...unsupportedLayers, ...childUnsupportedLayers]; } } return { layers, unsupportedLayers }; } /** * Check if layer has supported CRS * @param layer */ async function checkSupportedIndexCRS(layer) { try { const layerJson = await load(layer.url, JSONLoader); // @ts-expect-error const wkid = layerJson?.spatialReference?.wkid; if (wkid !== SUPPORTED_WKID) { throw new Error(NOT_SUPPORTED_CRS_ERROR); } } catch (error) { throw error; } }