UNPKG

terriajs

Version:

Geospatial data visualization platform.

459 lines 19.2 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import i18next from "i18next"; import uniqWith from "lodash-es/uniqWith"; import { computed, makeObservable, override, runInAction } from "mobx"; import GeographicTilingScheme from "terriajs-cesium/Source/Core/GeographicTilingScheme"; import JulianDate from "terriajs-cesium/Source/Core/JulianDate"; import WebMercatorTilingScheme from "terriajs-cesium/Source/Core/WebMercatorTilingScheme"; import URI from "urijs"; import AsyncLoader from "../../../Core/AsyncLoader"; import { isJsonObject } from "../../../Core/Json"; import TerriaError from "../../../Core/TerriaError"; import createDiscreteTimesFromIsoSegments from "../../../Core/createDiscreteTimes"; import createTransformerAllowUndefined from "../../../Core/createTransformerAllowUndefined"; import filterOutUndefined from "../../../Core/filterOutUndefined"; import isDefined from "../../../Core/isDefined"; import loadJson from "../../../Core/loadJson"; import replaceUnderscores from "../../../Core/replaceUnderscores"; import { scaleDenominatorToLevel } from "../../../Core/scaleToDenominator"; import ArcGisImageServerImageryProvider from "../../../Map/ImageryProvider/ArcGisImageServerImageryProvider"; import Reproject from "../../../Map/Vector/Reproject"; import CatalogMemberMixin from "../../../ModelMixins/CatalogMemberMixin"; import DiscretelyTimeVaryingMixin from "../../../ModelMixins/DiscretelyTimeVaryingMixin"; import MappableMixin from "../../../ModelMixins/MappableMixin"; import MinMaxLevelMixin from "../../../ModelMixins/MinMaxLevelMixin"; import UrlMixin from "../../../ModelMixins/UrlMixin"; import ArcGisImageServerCatalogItemTraits, { ArcGisImageServerAvailableRasterFunctionTraits, ArcGisImageServerRenderingRule } from "../../../Traits/TraitsClasses/ArcGisImageServerCatalogItemTraits"; import LegendTraits, { LegendItemTraits } from "../../../Traits/TraitsClasses/LegendTraits"; import CreateModel from "../../Definition/CreateModel"; import LoadableStratum from "../../Definition/LoadableStratum"; import StratumOrder from "../../Definition/StratumOrder"; import createStratumInstance from "../../Definition/createStratumInstance"; import getToken from "../../getToken"; import proxyCatalogItemUrl from "../proxyCatalogItemUrl"; import { getRectangleFromLayer } from "./ArcGisMapServerCatalogItem"; class ImageServerStratum extends LoadableStratum(ArcGisImageServerCatalogItemTraits) { _item; imageServer; _token; static stratumName = "arcgisImageserver"; constructor(_item, imageServer, _token) { super(); this._item = _item; this.imageServer = imageServer; this._token = _token; makeObservable(this); } duplicateLoadableStratum(newModel) { return new ImageServerStratum(newModel, this.imageServer, this._token); } static async load(item) { if (!isDefined(item.uri)) { throw new TerriaError({ title: i18next.t("models.arcGisImageServerCatalogItem.invalidUrlTitle"), message: i18next.t("models.arcGisImageServerCatalogItem.invalidUrlMessage") }); } let token; if (isDefined(item.tokenUrl) && isDefined(item.url)) { token = await getToken(item.terria, item.tokenUrl, item.url); } else if (isDefined(item.token)) { token = item.token; } let serviceUri = getBaseURI(item); if (isDefined(token)) { serviceUri = serviceUri.addQuery("token", token); } const serviceMetadata = await getJson(item, serviceUri); if (!isDefined(serviceMetadata)) { throw new TerriaError({ title: i18next.t("models.arcGisService.invalidServerTitle"), message: i18next.t("models.arcGisService.invalidServerMessage") }); } if (!serviceMetadata.capabilities?.includes("Image")) throw new TerriaError({ title: i18next.t("models.arcGisImageServerCatalogItem.invalidServiceTitle"), message: i18next.t("models.arcGisImageServerCatalogItem.invalidServiceMessage") }); // Add any Proj4 definitions if necessary const epsgCode = serviceMetadata.fullExtent.spatialReference?.latestWkid ?? serviceMetadata.fullExtent.spatialReference?.wkid; if (epsgCode && item.terria.configParameters.proj4ServiceBaseUrl) { await Reproject.checkProjection(item.terria.configParameters.proj4ServiceBaseUrl, `EPSG:${epsgCode}`); } const stratum = new ImageServerStratum(item, serviceMetadata, token); return stratum; } get name() { return replaceUnderscores(this.imageServer.name); } get cacheDuration() { return "1d"; } get rectangle() { const rectangle = { west: Infinity, south: Infinity, east: -Infinity, north: -Infinity }; getRectangleFromLayer(this.imageServer.fullExtent, rectangle); if (rectangle.west === Infinity || rectangle.south === Infinity || rectangle.east === -Infinity || rectangle.north === -Infinity) return undefined; return rectangle; } get description() { return this.imageServer.description; } get attribution() { return this.imageServer.copyrightText; } get token() { return this._token; } /** Disable pre-cached tiles if we are making dynamic requests - using parameters, time or rendering rule. */ get usePreCachedTiles() { if (this._item.parameters || this._item.currentDiscreteJulianDate || this._item.renderingRule.rasterFunction) return false; // We only support web mercator or wgs84 if (isDefined(this.imageServer.tileInfo)) { const wkid = this.imageServer.tileInfo.spatialReference?.latestWkid ?? this.imageServer.tileInfo.spatialReference?.wkid; if (wkid === 102100 || wkid === 102113 || wkid === 3857 || wkid === 4326) return true; } return false; } /** Override wkid to web mercator if using pre-cached tiles (and web mercator is supported) */ get wkid() { if (this._item.usePreCachedTiles) { const wkid = this.imageServer.tileInfo?.spatialReference.wkid; if (wkid === 102100 || wkid === 102113 || wkid === 3857 || wkid === 4326) return wkid; } } get tileHeight() { if (this._item.usePreCachedTiles) return this.imageServer.tileInfo?.rows; } get tileWidth() { if (this._item.usePreCachedTiles) return this.imageServer.tileInfo?.cols; } get maximumScale() { return this.imageServer.maxScale; } get maximumLevel() { const maximumLevelFromScale = scaleDenominatorToLevel(this._item.maximumScale, true, false); // Make sure the maximum level is not higher than the maximum level of the server tiles if (this._item.usePreCachedTiles && this.imageServer.tileInfo?.lods) return Math.min(this.imageServer.tileInfo.lods[this.imageServer.tileInfo.lods.length - 1].level, maximumLevelFromScale ?? Infinity); return maximumLevelFromScale; } get minimumLevel() { if (this._item.usePreCachedTiles && this.imageServer.tileInfo?.lods) return this.imageServer.tileInfo.lods[0].level; } get allowRasterFunction() { return this.imageServer.allowRasterFunction; } get availableRasterFunctions() { if (!this._item.allowRasterFunction) return []; return this.imageServer?.rasterFunctionInfos .filter((rasterFn) => rasterFn.name && rasterFn.name !== "None") .map((rasterFn) => { return createStratumInstance(ArcGisImageServerAvailableRasterFunctionTraits, { name: rasterFn.name, description: rasterFn.description !== "A raster function template." ? rasterFn.description : undefined, help: rasterFn.help }); }); } get disableRasterFunctionSelectors() { return !this._item.allowRasterFunction; } } __decorate([ computed ], ImageServerStratum.prototype, "usePreCachedTiles", null); StratumOrder.addLoadStratum(ImageServerStratum.stratumName); class ImageServerLegendStratum extends LoadableStratum(ArcGisImageServerCatalogItemTraits) { _item; _legends; static stratumName = "arcgisImageserverLegend"; constructor(_item, _legends) { super(); this._item = _item; this._legends = _legends; makeObservable(this); } duplicateLoadableStratum(newModel) { return new ImageServerLegendStratum(newModel, this._legends); } static async load(item) { if (!isDefined(item.uri)) { throw new TerriaError({ title: i18next.t("models.arcGisImageServerCatalogItem.invalidUrlTitle"), message: i18next.t("models.arcGisImageServerCatalogItem.invalidUrlMessage") }); } let legendUri = getBaseURI(item).segment("legend"); legendUri.addQuery(item.flattenedParameters); // Note we don't need to fetch token from tokenUrl here - as ImageServerStratum handles that, and will populate `token` trait with the response if (isDefined(item.token)) { legendUri = legendUri.addQuery("token", item.token); } const legendMetadata = await getJson(item, legendUri); const stratum = new ImageServerLegendStratum(item, legendMetadata); return stratum; } get legends() { const noDataRegex = /^No[\s_-]?Data$/i; const labelsRegex = /_Labels$/; let items = []; (this._legends?.layers || []).forEach((l) => { if (noDataRegex.test(l.layerName) || labelsRegex.test(l.layerName)) { return; } l.legend?.forEach((leg) => { const title = replaceUnderscores(leg.label !== "" ? leg.label : l.layerName); const dataUrl = "data:" + leg.contentType + ";base64," + leg.imageData; items.push(createStratumInstance(LegendItemTraits, { title, imageUrl: dataUrl, imageWidth: leg.width, imageHeight: leg.height })); }); }); items = uniqWith(items, (a, b) => a.imageUrl === b.imageUrl); return [createStratumInstance(LegendTraits, { items })]; } } __decorate([ computed ], ImageServerLegendStratum.prototype, "legends", null); StratumOrder.addLoadStratum(ImageServerLegendStratum.stratumName); export default class ArcGisImageServerCatalogItem extends UrlMixin(DiscretelyTimeVaryingMixin(MinMaxLevelMixin(CatalogMemberMixin(MappableMixin(CreateModel(ArcGisImageServerCatalogItemTraits)))))) { static type = "esri-imageServer"; _legendStratumLoader = new AsyncLoader(this.forceLoadLegends.bind(this)); constructor(...args) { super(...args); makeObservable(this); } get typeName() { return i18next.t("models.arcGisImageServerCatalogItem.name"); } get type() { return ArcGisImageServerCatalogItem.type; } async forceLoadMetadata() { const stratum = await ImageServerStratum.load(this); runInAction(() => { this.strata.set(ImageServerStratum.stratumName, stratum); }); await this._legendStratumLoader.load(); } async forceLoadLegends() { const stratum = await ImageServerLegendStratum.load(this); runInAction(() => { this.strata.set(ImageServerLegendStratum.stratumName, stratum); }); } forceLoadMapItems() { return Promise.resolve(); } get discreteTimes() { const imageServerStratum = this.strata.get(ImageServerStratum.stratumName); if (imageServerStratum?.imageServer.timeInfo === undefined) return undefined; const result = []; createDiscreteTimesFromIsoSegments(result, new Date(imageServerStratum.imageServer.timeInfo.timeExtent[0]).toISOString(), new Date(imageServerStratum.imageServer.timeInfo.timeExtent[1]).toISOString(), undefined, this.maxRefreshIntervals); return result; } get _currentImageryParts() { // Make sure legend stays up to date this._legendStratumLoader.load(); const imageryProvider = this._createImageryProvider(this.currentDiscreteJulianDate); if (imageryProvider) { return { imageryProvider, alpha: this.opacity, show: this.show, clippingRectangle: this.clipToRectangle ? this.cesiumRectangle : undefined }; } } get _nextImageryParts() { if (this.terria.timelineStack.contains(this) && !this.isPaused && this.nextDiscreteTimeTag) { const imageryProvider = this._createImageryProvider(this.nextDiscreteJulianDate); if (imageryProvider) { imageryProvider.enablePickFeatures = false; return { imageryProvider, alpha: 0.0, show: true, clippingRectangle: this.clipToRectangle ? this.cesiumRectangle : undefined }; } } else { return undefined; } } /** Flatten nested JSON parameters (stringify them). These are applied onto ArcGisImageServerImageryProvider requests. * This will include renderingRule and bandIds if they are set. */ get flattenedParameters() { const params = Object.entries(this.parameters ?? {}).reduce((acc, [key, value]) => { if (isJsonObject(value)) acc[key] = JSON.stringify(value); else acc[key] = value; return acc; }, {}); if (this.renderingRule.rasterFunction) params.renderingRule = JSON.stringify(this.traits["renderingRule"].toJson(this.renderingRule)); if (this.bandIds) params.bandIds = this.bandIds.join(","); return params; } _createImageryProvider = createTransformerAllowUndefined((time) => { if (!isDefined(this.url)) { return undefined; } const params = { ...this.flattenedParameters }; if (time) params.time = JulianDate.toDate(time).getTime(); let tilingScheme; if (this.wkid === 102100 || this.wkid === 102113 || this.wkid === 3857) { tilingScheme = new WebMercatorTilingScheme(); } else if (this.wkid === 4326) { tilingScheme = new GeographicTilingScheme(); } else { throw TerriaError.from(`Tile spatial reference WKID ${this.wkid} is not supported.`); } return new ArcGisImageServerImageryProvider({ url: cleanAndProxyUrl(this, this.url), tilingScheme: tilingScheme, maximumLevel: this.maximumLevel, minimumLevel: this.minimumLevel, tileHeight: this.tileHeight, tileWidth: this.tileWidth, parameters: params, enablePickFeatures: this.allowFeaturePicking, usePreCachedTiles: this.usePreCachedTiles, token: this.token, credit: this.attribution ?? "" }); }); get mapItems() { if (this.isLoadingMetadata) return []; return [this._currentImageryParts, this._nextImageryParts].filter(isDefined); } get selectableDimensions() { return filterOutUndefined([ ...super.selectableDimensions, this.rasterFunctionSelectableDimensions ]); } get rasterFunctionSelectableDimensions() { if (this.disableRasterFunctionSelectors) return undefined; return { id: "raster-functions", name: i18next.t("models.arcGisImageServerCatalogItem.rasterFunction"), options: this.availableRasterFunctions.map((rasterFn) => ({ id: rasterFn.name, name: rasterFn.name, description: rasterFn.description })), selectedId: this.renderingRule?.rasterFunction, allowUndefined: true, undefinedLabel: "Default", setDimensionValue: (strata, rasterFunction) => { if (!this.renderingRule) { this.setTrait(strata, "renderingRule", createStratumInstance(ArcGisImageServerRenderingRule, { rasterFunction })); } else { this.renderingRule.setTrait(strata, "rasterFunction", rasterFunction); } } }; } } __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "discreteTimes", null); __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "_currentImageryParts", null); __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "_nextImageryParts", null); __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "flattenedParameters", null); __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "mapItems", null); __decorate([ override ], ArcGisImageServerCatalogItem.prototype, "selectableDimensions", null); __decorate([ computed ], ArcGisImageServerCatalogItem.prototype, "rasterFunctionSelectableDimensions", null); function getBaseURI(item) { const uri = new URI(item.url); const lastSegment = uri.segment(-1); if (lastSegment && lastSegment.match(/\d+/)) { uri.segment(-1, ""); } return uri; } async function getJson(item, uri) { try { const response = await loadJson(proxyCatalogItemUrl(item, uri.addQuery("f", "json").toString())); return response; } catch (err) { console.log(err); return undefined; } } function cleanAndProxyUrl(catalogItem, url) { return proxyCatalogItemUrl(catalogItem, cleanUrl(url)); } function cleanUrl(url) { // Strip off the search portion of the URL const uri = new URI(url); uri.search(""); return uri.toString(); } //# sourceMappingURL=ArcGisImageServerCatalogItem.js.map