Skip to content

Commit

Permalink
Merge pull request #75 from sentinel-hub/feature/legend-info
Browse files Browse the repository at this point in the history
Feature/legend info
  • Loading branch information
Ardweaden authored May 15, 2020
2 parents 0bf488b + f59e081 commit 459af0b
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 21 deletions.
13 changes: 2 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BBox } from 'src/bbox';
import { CRS_EPSG4326, CRS_EPSG3857, CRS_WGS84, SUPPORTED_CRS_OBJ } from 'src/crs';
import { setAuthToken, isAuthTokenSet, requestAuthToken } from 'src/auth';
import { ApiType, MimeTypes, OrbitDirection, PreviewMode, MosaickingOrder } from 'src/layer/const';
import { ApiType, MimeTypes, OrbitDirection, PreviewMode } from 'src/layer/const';
import { setDebugEnabled } from 'src/utils/debug';

import { LayersFactory } from 'src/layer/LayersFactory';
Expand Down Expand Up @@ -40,14 +40,8 @@ import { Landsat8AWSLayer } from 'src/layer/Landsat8AWSLayer';
import { BYOCLayer } from 'src/layer/BYOCLayer';
import { ProcessingDataFusionLayer } from 'src/layer/ProcessingDataFusionLayer';

import {
legacyGetMapFromUrl,
legacyGetMapWmsUrlFromParams,
legacyGetMapFromParams,
parseLegacyWmsGetMapParams,
} from 'src/legacyCompat';
import { legacyGetMapFromUrl, legacyGetMapWmsUrlFromParams, legacyGetMapFromParams } from 'src/legacyCompat';
import { AcquisitionMode, Polarization, Resolution } from 'src/layer/S1GRDAWSEULayer';
import { LocationIdSHv3 } from 'src/layer/const';
import { registerAxiosCacheRetryInterceptors } from 'src/utils/axiosInterceptors';
import { CancelToken, isCancelled, RequestConfiguration } from 'src/utils/cancelRequests';

Expand Down Expand Up @@ -104,10 +98,8 @@ export {
Resolution,
OrbitDirection,
PreviewMode,
MosaickingOrder,
S3SLSTRView,
BBox,
LocationIdSHv3,
setDebugEnabled,
CancelToken,
isCancelled,
Expand All @@ -116,5 +108,4 @@ export {
legacyGetMapFromUrl,
legacyGetMapWmsUrlFromParams,
legacyGetMapFromParams,
parseLegacyWmsGetMapParams,
};
8 changes: 6 additions & 2 deletions src/layer/AbstractLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import { getAxiosReqParams, RequestConfiguration } from 'src/utils/cancelRequest
interface ConstructorParameters {
title?: string | null;
description?: string | null;
legendUrl?: string | null;
}

export class AbstractLayer {
public title: string | null = null;
public description: string | null = null;
public readonly dataset: Dataset | null = null;
public legendUrl: string | null = null;

public constructor({ title = null, description = null }: ConstructorParameters) {
public constructor({ title = null, description = null, legendUrl = null }: ConstructorParameters) {
this.title = title;
this.description = description;
this.legendUrl = legendUrl;
}

public async getMap(params: GetMapParams, api: ApiType, reqConfig?: RequestConfiguration): Promise<Blob> {
Expand Down Expand Up @@ -266,5 +269,6 @@ export class AbstractLayer {
throw new Error('getStats() not implemented for this dataset');
}

public async updateLayerFromServiceIfNeeded(): Promise<void> {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async updateLayerFromServiceIfNeeded(reqConfig?: RequestConfiguration): Promise<void> {}
}
26 changes: 25 additions & 1 deletion src/layer/AbstractSentinelHubV1OrV2Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { wmsGetMapUrl } from 'src/layer/wms';
import { AbstractLayer } from 'src/layer/AbstractLayer';
import { CRS_EPSG4326, findCrsFromUrn } from 'src/crs';
import { fetchGetCapabilitiesXml } from 'src/layer/utils';
import { getAxiosReqParams, RequestConfiguration } from 'src/utils/cancelRequests';

interface ConstructorParameters {
Expand All @@ -29,6 +30,7 @@ interface ConstructorParameters {
mosaickingOrder?: MosaickingOrder | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
}

// this class provides any SHv1- or SHv2-specific (EO Cloud) functionality to the subclasses:
Expand All @@ -47,8 +49,9 @@ export class AbstractSentinelHubV1OrV2Layer extends AbstractLayer {
mosaickingOrder = null,
title = null,
description = null,
legendUrl = null,
}: ConstructorParameters) {
super({ title, description });
super({ title, description, legendUrl });
if (!layerId || !instanceId) {
throw new Error('Parameters instanceId and layerId must be specified!');
}
Expand Down Expand Up @@ -253,4 +256,25 @@ export class AbstractSentinelHubV1OrV2Layer extends AbstractLayer {
}
return data;
}

public async updateLayerFromServiceIfNeeded(reqConfig?: RequestConfiguration): Promise<void> {
if (this.instanceId === null || this.layerId === null) {
throw new Error(
"Additional data can't be fetched from service because instanceId and layerId are not defined",
);
}
const baseUrl = `${this.dataset.shServiceHostname}v1/wms/${this.instanceId}`;
const capabilities = await fetchGetCapabilitiesXml(baseUrl, reqConfig);
const layer = capabilities.WMS_Capabilities.Capability[0].Layer[0].Layer.find(
layerInfo => this.layerId === layerInfo.Name[0],
);
if (!layer) {
throw new Error('Layer not found');
}
const legendUrl =
layer.Style && layer.Style[0].LegendURL
? layer.Style[0].LegendURL[0].OnlineResource[0]['$']['xlink:href']
: null;
this.legendUrl = legendUrl;
}
}
12 changes: 11 additions & 1 deletion src/layer/AbstractSentinelHubV3Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface ConstructorParameters {
mosaickingOrder?: MosaickingOrder | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
}

// this class provides any SHv3-specific functionality to the subclasses:
Expand All @@ -40,6 +41,7 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
protected evalscript: string | null;
protected evalscriptUrl: string | null;
protected dataProduct: string | null;
public legend?: any[] | null;
protected evalscriptWasConvertedToV3: boolean | null;
public mosaickingOrder: MosaickingOrder | null; // public because ProcessingDataFusionLayer needs to read it directly

Expand All @@ -52,8 +54,9 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
mosaickingOrder = null,
title = null,
description = null,
legendUrl = null,
}: ConstructorParameters) {
super({ title, description });
super({ title, description, legendUrl });
if (
(layerId === null || instanceId === null) &&
evalscript === null &&
Expand Down Expand Up @@ -103,6 +106,9 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
...l.datasourceDefaults,
evalscript: l.styles[0].evalScript,
dataProduct: l.styles[0].dataProduct,
legend: l.styles.find((s: any) => s.name === l.defaultStyleName)
? l.styles.find((s: any) => s.name === l.defaultStyleName).legend
: null,
}));

const layerParams = layersParams.find((l: any) => l.layerId === this.layerId);
Expand Down Expand Up @@ -443,6 +449,10 @@ export class AbstractSentinelHubV3Layer extends AbstractLayer {
return res.data;
}

public async updateLayerFromServiceIfNeeded(reqConfig: RequestConfiguration): Promise<void> {
const layerParams = await this.fetchLayerParamsFromSHServiceV3(reqConfig);
this.legend = layerParams['legend'] ? layerParams['legend'] : null;
}
protected getConvertEvalscriptBaseUrl(): string {
const shServiceHostname = this.getShServiceHostname();
return `${shServiceHostname}api/v1/process/convertscript?datasetType=${this.dataset.shProcessingApiDatasourceAbbreviation}`;
Expand Down
1 change: 1 addition & 0 deletions src/layer/AbstractSentinelHubV3WithCCLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface ConstructorParameters {
mosaickingOrder?: MosaickingOrder | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
maxCloudCoverPercent?: number | null;
}

Expand Down
13 changes: 11 additions & 2 deletions src/layer/LayersFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,13 @@ export class LayersFactory {
layerInfo.dataset && LayersFactory.DATASET_FROM_JSON_GETCAPAPABILITIES[layerInfo.dataset]
? LayersFactory.DATASET_FROM_JSON_GETCAPAPABILITIES[layerInfo.dataset]
: null,
legendUrl: layerInfo.legendUrl,
}));

const filteredLayersInfos =
filterLayers === null ? layersInfos : layersInfos.filter(l => filterLayers(l.layerId, l.dataset));

return filteredLayersInfos.map(({ layerId, dataset, title, description }) => {
return filteredLayersInfos.map(({ layerId, dataset, title, description, legendUrl }) => {
if (!dataset) {
return new WmsLayer({ baseUrl, layerId, title, description });
}
Expand All @@ -162,6 +163,7 @@ export class LayersFactory {
dataProduct: null,
title,
description,
legendUrl,
});
});
}
Expand Down Expand Up @@ -217,13 +219,20 @@ export class LayersFactory {
title: layerInfo.Title[0],
description: layerInfo.Abstract ? layerInfo.Abstract[0] : null,
dataset: null,
legendUrl:
layerInfo.Style && layerInfo.Style[0].LegendURL
? layerInfo.Style[0].LegendURL[0].OnlineResource[0]['$']['xlink:href']
: layerInfo.Layer && layerInfo.Layer[0].Style && layerInfo.Layer[0].Style[0].LegendURL
? layerInfo.Layer[0].Style[0].LegendURL[0].OnlineResource[0]['$']['xlink:href']
: null,
}));

const filteredLayersInfos =
filterLayers === null ? layersInfos : layersInfos.filter(l => filterLayers(l.layerId, l.dataset));

return filteredLayersInfos.map(
({ layerId, title, description }) => new WmsLayer({ baseUrl, layerId, title, description }),
({ layerId, title, description, legendUrl }) =>
new WmsLayer({ baseUrl, layerId, title, description, legendUrl }),
);
}
}
5 changes: 4 additions & 1 deletion src/layer/S1GRDAWSEULayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface ConstructorParameters {
dataProduct?: string | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
acquisitionMode?: AcquisitionMode | null;
polarization?: Polarization | null;
resolution?: Resolution | null;
Expand Down Expand Up @@ -71,14 +72,15 @@ export class S1GRDAWSEULayer extends AbstractSentinelHubV3Layer {
dataProduct = null,
title = null,
description = null,
legendUrl = null,
acquisitionMode = null,
polarization = null,
resolution = null,
orthorectify = false,
backscatterCoeff = BackscatterCoeff.GAMMA0_ELLIPSOID,
orbitDirection = null,
}: ConstructorParameters) {
super({ instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description });
super({ instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description, legendUrl });
this.acquisitionMode = acquisitionMode;
this.polarization = polarization;
this.resolution = resolution;
Expand All @@ -105,6 +107,7 @@ export class S1GRDAWSEULayer extends AbstractSentinelHubV3Layer {
this.backscatterCoeff = layerParams['backCoeff'];
this.orthorectify = layerParams['orthorectify'];
this.orbitDirection = layerParams['orbitDirection'] ? layerParams['orbitDirection'] : null;
this.legend = layerParams['legend'] ? layerParams['legend'] : null;
}

protected async updateProcessingGetMapPayload(
Expand Down
1 change: 1 addition & 0 deletions src/layer/S3SLSTRLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface ConstructorParameters {
dataProduct?: string | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
maxCloudCoverPercent?: number | null;
view?: S3SLSTRView | null;
}
Expand Down
4 changes: 3 additions & 1 deletion src/layer/S5PL2Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface ConstructorParameters {
dataProduct?: string | null;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
productType?: ProductType | null;
maxCloudCoverPercent?: number | null;
minQa?: number | null;
Expand All @@ -57,11 +58,12 @@ export class S5PL2Layer extends AbstractSentinelHubV3Layer {
dataProduct = null,
title = null,
description = null,
legendUrl = null,
productType = null,
maxCloudCoverPercent = 100,
minQa = null,
}: ConstructorParameters) {
super({ instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description });
super({ instanceId, layerId, evalscript, evalscriptUrl, dataProduct, title, description, legendUrl });
this.productType = productType;
this.maxCloudCoverPercent = maxCloudCoverPercent;
this.minQa = minQa;
Expand Down
36 changes: 34 additions & 2 deletions src/layer/WmsLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ interface ConstructorParameters {
layerId?: string;
title?: string | null;
description?: string | null;
legendUrl?: string | null;
}

export class WmsLayer extends AbstractLayer {
// The URL of the WMS service, for example: "https://services.sentinel-hub.com/ogc/wms/<instance-id>/"
protected baseUrl: string;
protected layerId: string;

public constructor({ baseUrl, layerId, title = null, description = null }: ConstructorParameters) {
super({ title, description });
public constructor({
baseUrl,
layerId,
title = null,
description = null,
legendUrl = null,
}: ConstructorParameters) {
super({ title, description, legendUrl });
this.baseUrl = baseUrl;
this.layerId = layerId;
}
Expand Down Expand Up @@ -90,4 +97,29 @@ export class WmsLayer extends AbstractLayer {
found.sort((a, b) => b.unix() - a.unix());
return found.map(m => m.toDate());
}

public async updateLayerFromServiceIfNeeded(reqConfig?: RequestConfiguration): Promise<void> {
if (this.legendUrl) {
return;
}
if (this.baseUrl === null || this.layerId === null) {
throw new Error(
"Additional data can't be fetched from service because baseUrl and layerId are not defined",
);
}
const capabilities = await fetchGetCapabilitiesXml(this.baseUrl, reqConfig);
const layer = capabilities.WMS_Capabilities.Capability[0].Layer[0].Layer.find(
layer => this.layerId === layer.Name[0],
);
if (!layer) {
throw new Error('Layer not found');
}
const legendUrl =
layer.Style && layer.Style[0].LegendURL
? layer.Style[0].LegendURL[0].OnlineResource[0]['$']['xlink:href']
: layer.Layer && layer.Layer[0].Style && layer.Layer[0].Style[0].LegendURL
? layer.Layer[0].Style[0].LegendURL[0].OnlineResource[0]['$']['xlink:href']
: null;
this.legendUrl = legendUrl;
}
}
1 change: 1 addition & 0 deletions src/layer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type GetCapabilitiesXml = {
Abstract: string[];
Style: any[]; // Depending on the service, it can be an array of strings or an array of objects
Dimension?: any[];
Layer?: any[];
},
];
},
Expand Down

0 comments on commit 459af0b

Please sign in to comment.