terriajs
Version:
Geospatial data visualization platform.
459 lines • 19.2 kB
JavaScript
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