UNPKG

terriajs

Version:

Geospatial data visualization platform.

316 lines (282 loc) 9.56 kB
import i18next from "i18next"; import { computed, runInAction, makeObservable } from "mobx"; import URI from "urijs"; import isDefined from "../../../Core/isDefined"; import { JsonObject } from "../../../Core/Json"; import loadJson from "../../../Core/loadJson"; import TerriaError from "../../../Core/TerriaError"; import MappableMixin from "../../../ModelMixins/MappableMixin"; import CatalogMemberMixin from "../../../ModelMixins/CatalogMemberMixin"; import UrlMixin from "../../../ModelMixins/UrlMixin"; import { FeatureInfoTemplateTraits } from "../../../Traits/TraitsClasses/FeatureInfoTraits"; import SenapsLocationsCatalogItemTraits from "../../../Traits/TraitsClasses/SenapsLocationsCatalogItemTraits"; import CommonStrata from "../../Definition/CommonStrata"; import CreateModel from "../../Definition/CreateModel"; import createStratumInstance from "../../Definition/createStratumInstance"; import GeoJsonCatalogItem from "./GeoJsonCatalogItem"; import LoadableStratum from "../../Definition/LoadableStratum"; import { BaseModel } from "../../Definition/Model"; import proxyCatalogItemUrl from "../proxyCatalogItemUrl"; import { ModelConstructorParameters } from "../../Definition/Model"; import StratumOrder from "../../Definition/StratumOrder"; export interface SenapsFeature { type: string; properties: { id: string; description: string; endpoint: string; hasStreams: boolean | null; streamIds: string[]; }; geometry: JsonObject; } export interface SenapsFeatureCollection { type: string; features: SenapsFeature[]; } interface SenapsStream { id: string; } interface SenapsStreamResponse { _embedded?: { streams: SenapsStream[]; }; count: number; } interface SenapsLocation { id: string; description: string; streamIds: string[]; geojson: JsonObject; _links: { self: { href: string; }; }; } interface LocationsData { _embedded: { locations: SenapsLocation[]; }; } export class SenapsLocationsStratum extends LoadableStratum( SenapsLocationsCatalogItemTraits ) { static stratumName = "SenapsLocations"; constructor( private readonly senapsLocationsCatalogItem: SenapsLocationsCatalogItem, private readonly geojsonItem: GeoJsonCatalogItem ) { super(); this.geojsonItem = geojsonItem; } duplicateLoadableStratum(newModel: BaseModel): this { return new SenapsLocationsStratum( newModel as SenapsLocationsCatalogItem, this.geojsonItem ) as this; } static async load(senapsLocationsCatalogItem: SenapsLocationsCatalogItem) { const locationsUrl = senapsLocationsCatalogItem._constructLocationsUrl(); function addStreamIds(f: SenapsFeature, index: number, streamData: any) { const sd: SenapsStreamResponse = streamData[index]; if (sd.count === 0) { f.properties.hasStreams = false; } else if (sd._embedded !== undefined) { f.properties.streamIds = sd._embedded.streams.map( (s: SenapsStream) => s.id ); f.properties.hasStreams = true; } } try { const locationsResponse: LocationsData = await loadJson( proxyCatalogItemUrl(senapsLocationsCatalogItem, locationsUrl, "0d") ); const locations = locationsResponse._embedded.locations; const streamPromises = []; for (let i = 0; i < locations.length; i++) { const location = locations[i]; const locationId = location.id; const streamUrl = proxyCatalogItemUrl( senapsLocationsCatalogItem, senapsLocationsCatalogItem._constructStreamsUrl(locationId), "0d" ); streamPromises.push(loadJson(streamUrl)); } const streamData = await Promise.all(streamPromises); const fc: SenapsFeatureCollection = { type: "FeatureCollection", features: locations.map((site: SenapsLocation, i: number) => { const f: SenapsFeature = { type: "Feature", properties: { id: site.id, description: site.description, endpoint: site._links.self.href, hasStreams: null, streamIds: [] }, geometry: site.geojson }; addStreamIds(f, i, streamData); return f; }) }; const geojsonCatalogItem = new GeoJsonCatalogItem( undefined, senapsLocationsCatalogItem.terria ); geojsonCatalogItem.setTrait( CommonStrata.definition, "geoJsonData", fc as any as JsonObject ); geojsonCatalogItem.setTrait( CommonStrata.definition, "clampToGround", true ); if (isDefined(senapsLocationsCatalogItem.style)) { geojsonCatalogItem.setTrait( CommonStrata.definition, "style", senapsLocationsCatalogItem.style ); } if (!senapsLocationsCatalogItem.url) { throw new TerriaError({ title: i18next.t("models.senaps.retrieveErrorTitle"), message: i18next.t("models.senaps.missingSenapsBaseUrl") }); } const proxiedBaseUrl = proxyCatalogItemUrl( senapsLocationsCatalogItem, senapsLocationsCatalogItem.url, "0d" ); const featureInfo = createStratumInstance(FeatureInfoTemplateTraits, { template: `<h4>${i18next.t( "models.senaps.locationHeadingFeatureInfo" )}: {{id}}</h4> <h5 style="margin-bottom:5px;">${i18next.t( "models.senaps.availableStreamsHeadingFeatureInfo" )}</h5> {{#hasStreams}} <ul>{{#streamIds}} <li>{{.}}</li> {{/streamIds}}</ul> <br/> <chart identifier='{{id}}' title='{{id}}' sources='${proxiedBaseUrl}/observations?streamid={{#terria.urlEncodeComponent}}{{streamIds}}{{/terria.urlEncodeComponent}}&limit=1440&media=csv&csvheader=false&sort=descending,${proxiedBaseUrl}/observations?streamid={{#terria.urlEncodeComponent}}{{streamIds}}{{/terria.urlEncodeComponent}}&limit=7200&media=csv&csvheader=false&sort=descending' source-names='1d,5d' downloads='${proxiedBaseUrl}/observations?streamid={{#terria.urlEncodeComponent}}{{streamIds}}{{/terria.urlEncodeComponent}}&limit=1440&media=csv&csvheader=false&sort=descending,${proxiedBaseUrl}/observations?streamid={{#terria.urlEncodeComponent}}{{streamIds}}{{/terria.urlEncodeComponent}}&limit=7200&media=csv&csvheader=false&sort=descending' download-names='1d,5d' > </chart> {{/hasStreams}} {{^hasStreams}} <br/><br/> {{/hasStreams}} ` }); senapsLocationsCatalogItem.setTrait( CommonStrata.definition, "featureInfoTemplate", featureInfo ); (await geojsonCatalogItem.loadMapItems()).throwIfError(); return new SenapsLocationsStratum( senapsLocationsCatalogItem, geojsonCatalogItem ); } catch (e: any) { throw TerriaError.from(e, { title: i18next.t("models.senaps.retrieveErrorTitle"), message: i18next.t( e.statusCode === 401 ? "models.senaps.missingKeyErrorMessage" : "models.senaps.generalErrorMessage" ) }); } } get dataSource(): GeoJsonCatalogItem { return this.geojsonItem; } } StratumOrder.addLoadStratum(SenapsLocationsStratum.stratumName); class SenapsLocationsCatalogItem extends MappableMixin( UrlMixin(CatalogMemberMixin(CreateModel(SenapsLocationsCatalogItemTraits))) ) { static readonly type = "senaps-locations"; constructor(...args: ModelConstructorParameters) { super(...args); makeObservable(this); } get type() { return SenapsLocationsCatalogItem.type; } get typeName() { return i18next.t("models.senaps.name"); } protected forceLoadMapItems(): Promise<void> { return SenapsLocationsStratum.load(this).then((stratum) => { if (stratum === undefined) return; runInAction(() => { this.strata.set(SenapsLocationsStratum.stratumName, stratum); }); }); } @computed get geoJsonItem() { const stratum = this.strata.get( SenapsLocationsStratum.stratumName ) as SenapsLocationsStratum; return isDefined(stratum) ? stratum.dataSource : undefined; } @computed get mapItems() { if (isDefined(this.geoJsonItem)) { return this.geoJsonItem.mapItems.map((mapItem) => { mapItem.show = this.show; return mapItem; }); } return []; } protected forceLoadMetadata(): Promise<void> { return Promise.resolve(); } _constructLocationsUrl() { if (!this.url) { throw new TerriaError({ title: i18next.t("models.senaps.retrieveErrorTitle"), message: i18next.t("models.senaps.missingSenapsBaseUrl") }); } const uri = new URI(`${this.url}/locations`); if (this.locationIdFilter !== undefined) { uri.setSearch("id", this.locationIdFilter); } uri.setSearch("count", "1000"); uri.setSearch("expand", "true"); return uri.toString(); } _constructStreamsUrl(locationId: string) { if (!this.url) { throw new TerriaError({ title: i18next.t("models.senaps.retrieveErrorTitle"), message: i18next.t("models.senaps.missingSenapsBaseUrl") }); } const uri = new URI(`${this.url}/streams`); if (this.streamIdFilter !== undefined) { uri.setSearch("id", this.streamIdFilter); } uri.setSearch("locationid", locationId); return uri.toString(); } } export default SenapsLocationsCatalogItem;