UNPKG

@itwin/core-frontend

Version:
192 lines • 10 kB
import { ArcGISMapLayerImageryProvider, ArcGisUtilities, AzureMapsLayerImageryProvider, BingMapsImageryLayerProvider, ImageryMapLayerTreeReference, MapBoxLayerImageryProvider, MapLayerFormat, MapLayerSource, MapLayerSourceStatus, TileUrlImageryProvider, WmsCapabilities, WmsMapLayerImageryProvider, WmtsCapabilities, WmtsMapLayerImageryProvider, } from "../internal"; /** Base class imagery map layer formats. * Subclasses should override formatId and [[MapLayerFormat.createImageryProvider]]. * @see [[MapLayerFormat]] * @beta */ export class ImageryMapLayerFormat extends MapLayerFormat { /** @internal */ static createMapLayerTree(layerSettings, layerIndex, iModel) { return new ImageryMapLayerTreeReference({ layerSettings, layerIndex, iModel }); } } class WmsMapLayerFormat extends ImageryMapLayerFormat { static formatId = "WMS"; static createImageryProvider(settings) { return new WmsMapLayerImageryProvider(settings); } static async validateSource(url, userName, password, ignoreCache) { const source = MapLayerSource.fromJSON({ name: "", formatId: WmsMapLayerFormat.formatId, url }); if (source === undefined) return { status: MapLayerSourceStatus.InvalidFormat }; source.userName = userName; source.password = password; return WmsMapLayerFormat.validate({ source, ignoreCache }); } static async validate(args) { const { source, ignoreCache } = args; const { url, userName, password } = source; try { let subLayers; const maxVisibleSubLayers = 50; const capabilities = await WmsCapabilities.create(url, (userName && password ? { user: userName, password } : undefined), ignoreCache, source.collectQueryParams()); if (capabilities !== undefined) { subLayers = capabilities.getSubLayers(false); const rootsSubLayer = subLayers?.find((sublayer) => sublayer.parent === undefined); const hasTooManyLayers = subLayers && subLayers.length > maxVisibleSubLayers; if (!Array.isArray(subLayers)) return { status: MapLayerSourceStatus.Valid, subLayers }; for (const subLayer of subLayers) { // In general for WMS, we prefer to have the children of root node visible, but not the root itself. // Thats simply to give more flexibility in the UI. // Two exceptions to this rule: If there are too many layers or the root node is not named. if (subLayer.id && subLayer.id === rootsSubLayer?.id && (!(subLayer.name && subLayer.name.length > 0) || hasTooManyLayers)) { subLayer.visible = true; break; // if root node is visible, don't bother turning ON any other layers } // Make children of the root node visible. if (subLayer.parent && subLayer.parent === rootsSubLayer?.id && !hasTooManyLayers) { const isUnnamedGroup = (layer) => { return layer.children && layer.children.length > 0 && (!layer.name || layer.name.length === 0); }; const makeChildrenVisible = (layers, layer) => { layer?.children?.forEach((childId) => { const childSubLayer = subLayers?.find((child) => child?.id === childId); if (childSubLayer) { childSubLayer.visible = true; if (isUnnamedGroup(childSubLayer)) makeChildrenVisible(layers, childSubLayer); } }); }; subLayer.visible = true; // If we got a unnamed group, make children visible recursively until we have a leaf or named group if (isUnnamedGroup(subLayer)) makeChildrenVisible(subLayers, subLayer); } } } return { status: MapLayerSourceStatus.Valid, subLayers }; } catch (err) { let status = MapLayerSourceStatus.InvalidUrl; if (err?.status === 401) { status = ((userName && password) ? MapLayerSourceStatus.InvalidCredentials : MapLayerSourceStatus.RequireAuth); } return { status }; } } } class WmtsMapLayerFormat extends ImageryMapLayerFormat { static formatId = "WMTS"; static createImageryProvider(settings) { return new WmtsMapLayerImageryProvider(settings); } static async validateSource(url, userName, password, ignoreCache) { const source = MapLayerSource.fromJSON({ name: "", formatId: WmtsMapLayerFormat.formatId, url }); if (source === undefined) return { status: MapLayerSourceStatus.InvalidFormat }; source.userName = userName; source.password = password; return WmtsMapLayerFormat.validate({ source, ignoreCache }); } static async validate(args) { const { source, ignoreCache } = args; const { url, userName, password } = source; try { const subLayers = []; const capabilities = await WmtsCapabilities.create(url, (userName && password ? { user: userName, password } : undefined), ignoreCache, source.collectQueryParams()); if (!capabilities) return { status: MapLayerSourceStatus.InvalidUrl }; // Only returns layer that can be published in the Google maps or WGS84 aligned tile trees. let supportedTms = []; const googleMapsTms = capabilities?.contents?.getGoogleMapsCompatibleTileMatrixSet(); if (googleMapsTms) { supportedTms = googleMapsTms; } const wsg84Tms = capabilities?.contents?.getEpsg4326CompatibleTileMatrixSet(); if (wsg84Tms) { supportedTms = supportedTms.concat(wsg84Tms); } if (supportedTms.length === 0) { // This WMTS server doesn't support either GoogleMaps or WSG84 return { status: MapLayerSourceStatus.InvalidCoordinateSystem }; } let subLayerId = 0; capabilities?.contents?.layers.forEach((layer) => { const hasSupportedTms = supportedTms?.some((tms) => { return layer.tileMatrixSetLinks.some((tmls) => tmls.tileMatrixSet === tms.identifier); }); if (hasSupportedTms) { subLayers.push({ name: layer.identifier, title: layer.title ?? layer.identifier, visible: (subLayers.length === 0), // Make the first layer visible. parent: undefined, children: undefined, id: subLayerId++, }); } }); // Return error if we could find a single compatible layer. if (subLayers.length === 0) return { status: MapLayerSourceStatus.InvalidTileTree }; return { status: MapLayerSourceStatus.Valid, subLayers }; } catch (err) { let status = MapLayerSourceStatus.InvalidUrl; if (err?.status === 401) { status = ((userName && password) ? MapLayerSourceStatus.InvalidCredentials : MapLayerSourceStatus.RequireAuth); } return { status }; } } } class ArcGISMapLayerFormat extends ImageryMapLayerFormat { static formatId = "ArcGIS"; static async validateSource(url, userName, password, ignoreCache) { const source = MapLayerSource.fromJSON({ name: "", formatId: WmtsMapLayerFormat.formatId, url }); if (source === undefined) return { status: MapLayerSourceStatus.InvalidFormat }; source.userName = userName; source.password = password; return WmtsMapLayerFormat.validate({ source, ignoreCache }); } static async validate(args) { const urlValidation = ArcGisUtilities.validateUrl(args.source.url, "MapServer"); if (urlValidation !== MapLayerSourceStatus.Valid) return { status: urlValidation }; // Some Map service supporting only tiles don't include the 'Map' capabilities, thus we can't make it mandatory. return ArcGisUtilities.validateSource({ ...args, capabilitiesFilter: [] }); } static createImageryProvider(settings) { return new ArcGISMapLayerImageryProvider(settings); } } // eslint-disable-next-line @typescript-eslint/no-unused-vars class AzureMapsMapLayerFormat extends ImageryMapLayerFormat { static formatId = "AzureMaps"; static createImageryProvider(settings) { return new AzureMapsLayerImageryProvider(settings); } } class BingMapsMapLayerFormat extends ImageryMapLayerFormat { static formatId = "BingMaps"; static createImageryProvider(settings) { return new BingMapsImageryLayerProvider(settings); } } class MapBoxImageryMapLayerFormat extends ImageryMapLayerFormat { static formatId = "MapboxImagery"; static createImageryProvider(settings) { return new MapBoxLayerImageryProvider(settings); } } class TileUrlMapLayerFormat extends ImageryMapLayerFormat { static formatId = "TileURL"; static createImageryProvider(settings) { return new TileUrlImageryProvider(settings); } } /** @internal */ export const internalMapLayerImageryFormats = [WmsMapLayerFormat, WmtsMapLayerFormat, ArcGISMapLayerFormat, /* AzureMapsMapLayerFormat, */ BingMapsMapLayerFormat, MapBoxImageryMapLayerFormat, TileUrlMapLayerFormat]; //# sourceMappingURL=MapLayerImageryFormats.js.map