@itwin/core-frontend
Version:
iTwin.js frontend components
192 lines • 10 kB
JavaScript
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