@itwin/core-frontend
Version:
iTwin.js frontend components
239 lines • 11.5 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module MapLayers
*/
import { compareStrings, expectDefined } from "@itwin/core-bentley";
import { BackgroundMapProvider, BackgroundMapType, BaseMapLayerSettings, ImageMapLayerSettings, } from "@itwin/core-common";
import { Point2d } from "@itwin/core-geometry";
import { IModelApp } from "../../IModelApp";
import { request } from "../../request/Request";
import { ArcGisUtilities, MapCartoRectangle } from "../internal";
/** Values for return codes from [[MapLayerSource.validateSource]]
* @public
*/
export var MapLayerSourceStatus;
(function (MapLayerSourceStatus) {
/** Layer source is valid */
MapLayerSourceStatus[MapLayerSourceStatus["Valid"] = 0] = "Valid";
/** Authorization has failed when accessing this layer source. */
MapLayerSourceStatus[MapLayerSourceStatus["InvalidCredentials"] = 1] = "InvalidCredentials";
/** Provided format id could not be resolved in [[MapLayerFormatRegistry]] */
MapLayerSourceStatus[MapLayerSourceStatus["InvalidFormat"] = 2] = "InvalidFormat";
/** The tiling schema of the source is not supported */
MapLayerSourceStatus[MapLayerSourceStatus["InvalidTileTree"] = 3] = "InvalidTileTree";
/** Could not not connect to remote server using the provided URL.*/
MapLayerSourceStatus[MapLayerSourceStatus["InvalidUrl"] = 4] = "InvalidUrl";
/** Authorization is required to access this map layer source. */
MapLayerSourceStatus[MapLayerSourceStatus["RequireAuth"] = 5] = "RequireAuth";
/** Map-layer coordinate system is not supported */
MapLayerSourceStatus[MapLayerSourceStatus["InvalidCoordinateSystem"] = 6] = "InvalidCoordinateSystem";
/** Format is not compatible with the URL provided.
*/
MapLayerSourceStatus[MapLayerSourceStatus["IncompatibleFormat"] = 7] = "IncompatibleFormat";
})(MapLayerSourceStatus || (MapLayerSourceStatus = {}));
/** A source for map layers. These may be catalogued for convenient use by users or applications.
* @public
*/
export class MapLayerSource {
formatId;
name;
url;
baseMap = false;
transparentBackground;
userName;
password;
/** List of query parameters that will get appended to the source URL that should be be persisted part of the JSON representation.
* @beta
*/
savedQueryParams;
/** List of query parameters that will get appended to the source URL that should *not* be be persisted part of the JSON representation.
* @beta
*/
unsavedQueryParams;
constructor(formatId = "WMS", name, url, baseMap = false, transparentBackground = true, savedQueryParams) {
this.formatId = formatId;
this.name = name;
this.url = url;
this.baseMap = baseMap;
this.transparentBackground = transparentBackground;
this.savedQueryParams = savedQueryParams;
}
static fromJSON(json) {
if (json === undefined)
return undefined;
return new MapLayerSource(json.formatId, json.name, json.url, json.baseMap, json.transparentBackground, json.queryParams);
}
async validateSource(ignoreCache) {
return IModelApp.mapLayerFormatRegistry.validateSource({ source: this, ignoreCache });
}
/** @internal*/
static fromBackgroundMapProps(props) {
const provider = BackgroundMapProvider.fromBackgroundMapProps(props);
const layerSettings = BaseMapLayerSettings.fromProvider(provider);
if (undefined !== layerSettings) {
const source = MapLayerSource.fromJSON(layerSettings);
if (source) {
source.baseMap = true;
return source;
}
}
return undefined;
}
toJSON() {
return { url: this.url, name: this.name, formatId: this.formatId, transparentBackground: this.transparentBackground, queryParams: this.savedQueryParams };
}
toLayerSettings(subLayers) {
// When MapLayerSetting is created from a MapLayerSource, sub-layers and credentials need to be set separately.
const layerSettings = ImageMapLayerSettings.fromJSON({ ...this, subLayers });
if (this.userName !== undefined || this.password !== undefined) {
layerSettings?.setCredentials(this.userName, this.password);
}
if (this.savedQueryParams) {
layerSettings.savedQueryParams = { ...this.savedQueryParams };
}
if (this.unsavedQueryParams) {
layerSettings.unsavedQueryParams = { ...this.unsavedQueryParams };
}
return layerSettings;
}
getCredentials() {
return this.userName && this.password ? { user: this.userName, password: this.password } : undefined;
}
/** Collect all query parameters
* @beta
*/
collectQueryParams() {
let queryParams = {};
if (this.savedQueryParams)
queryParams = { ...this.savedQueryParams };
if (this.unsavedQueryParams)
queryParams = { ...queryParams, ...this.unsavedQueryParams };
return queryParams;
}
}
/** A collection of [[MapLayerSource]] objects.
* @beta
*/
export class MapLayerSources {
_sources;
static _instance;
constructor(_sources) {
this._sources = _sources;
}
static getInstance() { return MapLayerSources._instance; }
findByName(name, baseMap = false) {
const nameTest = name.toLowerCase();
for (const source of this._sources)
if (source.baseMap === baseMap && source.name.toLowerCase().indexOf(nameTest) !== -1)
return source;
return undefined;
}
get layers() {
const layers = new Array();
this._sources.forEach((source) => {
if (!source.baseMap)
layers.push(source);
});
return layers;
}
get allSource() { return this._sources; }
get bases() {
const layers = new Array();
this._sources.forEach((source) => {
if (source.baseMap)
layers.push(source);
});
return layers;
}
static getBingMapLayerSource() {
const mapLayerSources = [];
// We know these hard-coded sources are valid, so ! is okay here.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: BackgroundMapType.Street } }));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: BackgroundMapType.Aerial } }));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: BackgroundMapType.Hybrid } }));
return mapLayerSources;
}
static getMapBoxLayerSource() {
const mapLayerSources = [];
// We know these hard-coded sources are valid, so ! is okay here.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: BackgroundMapType.Street } }));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: BackgroundMapType.Aerial } }));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: BackgroundMapType.Hybrid } }));
return mapLayerSources;
}
static async create(iModel, queryForPublicSources = false, addMapBoxSources = false) {
if (!queryForPublicSources && MapLayerSources._instance)
return MapLayerSources._instance;
if (!iModel)
iModel = IModelApp.viewManager.selectedView ? IModelApp.viewManager.selectedView.iModel : undefined;
let sourceRange = MapCartoRectangle.createMaximum();
if (iModel) {
const projectCenter = expectDefined(iModel.projectExtents.localXYZToWorld(.5, .5, .5));
const cartoCenter = iModel.spatialToCartographicFromEcef(projectCenter);
const globeRange = MapCartoRectangle.createMaximum();
const nearDelta = Point2d.create(globeRange.xLength() / 100, globeRange.yLength() / 100);
sourceRange = MapCartoRectangle.fromRadians(cartoCenter.longitude - nearDelta.x, cartoCenter.latitude - nearDelta.y, cartoCenter.longitude + nearDelta.x, cartoCenter.latitude + nearDelta.y);
}
const sources = new Array();
const urlSet = new Set();
const addSource = ((source) => {
if (!urlSet.has(source.url)) {
sources.push(source);
urlSet.add(source.url);
}
});
this.getBingMapLayerSource().forEach((source) => {
addSource(source);
});
if (addMapBoxSources) {
this.getMapBoxLayerSource().forEach((source) => {
addSource(source);
});
}
if (queryForPublicSources) {
const sourcesJson = await request(`${IModelApp.publicPath}assets/MapLayerSources.json`, "json");
for (const sourceJson of sourcesJson) {
const source = MapLayerSource.fromJSON(sourceJson);
if (source)
addSource(source);
}
(await ArcGisUtilities.getSourcesFromQuery(sourceRange)).forEach((queriedSource) => addSource(queriedSource));
}
sources.sort((a, b) => compareStrings(a.name.toLowerCase(), b.name.toLowerCase()));
const mapLayerSources = new MapLayerSources(sources);
MapLayerSources._instance = mapLayerSources;
return mapLayerSources;
}
static async addSourceToMapLayerSources(mapLayerSource) {
if (!MapLayerSources._instance || !mapLayerSource) {
return undefined;
}
MapLayerSources._instance._sources = MapLayerSources._instance._sources.filter((source) => {
return !(source.name === mapLayerSource.name || source.url === mapLayerSource.url);
});
MapLayerSources._instance._sources.push(mapLayerSource);
MapLayerSources._instance._sources.sort((a, b) => compareStrings(a.name.toLowerCase(), b.name.toLowerCase()));
return MapLayerSources._instance;
}
static removeLayerByName(name) {
if (!MapLayerSources._instance) {
return false;
}
// For now we only rely on the name
const lengthBeforeRemove = MapLayerSources._instance._sources.length;
MapLayerSources._instance._sources = MapLayerSources._instance._sources.filter((source) => {
return (source.name !== name);
});
return (lengthBeforeRemove !== MapLayerSources._instance._sources.length);
}
}
//# sourceMappingURL=MapLayerSources.js.map