@eodash/eodash 5.1.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/client/components/DashboardLayout.vue +1 -2
- package/core/client/components/EodashOverlay.vue +4 -5
- package/core/client/components/MobileLayout.vue +42 -21
- package/core/client/composables/index.js +54 -60
- package/core/client/eodashSTAC/EodashCollection.js +199 -108
- package/core/client/eodashSTAC/auth.js +86 -0
- package/core/client/eodashSTAC/createLayers.js +234 -4
- package/core/client/eodashSTAC/helpers.js +281 -59
- package/core/client/eodashSTAC/parquet.js +0 -13
- package/core/client/eodashSTAC/triggers.js +1 -1
- package/core/client/store/actions.js +14 -0
- package/core/client/store/stac.js +46 -8
- package/core/client/store/states.js +6 -0
- package/core/client/types.ts +206 -3
- package/core/client/utils/bands-editor/arithmetic.js +144 -0
- package/core/client/utils/bands-editor/colors.js +36 -0
- package/core/client/utils/bands-editor/dom.js +196 -0
- package/core/client/utils/bands-editor/exampleSchema.json +1320 -0
- package/core/client/utils/bands-editor/index.js +68 -0
- package/core/client/utils/bands-editor/rgb.js +102 -0
- package/core/client/utils/index.js +5 -2
- package/core/client/views/Dashboard.vue +1 -1
- package/core/client/vite-env.d.ts +122 -0
- package/dist/client/{DashboardLayout-ByVs1DrY.js → DashboardLayout-Cq15p4TH.js} +5 -6
- package/dist/client/{DynamicWebComponent-C3W7HSQm.js → DynamicWebComponent-Cv-fPRG1.js} +1 -1
- package/dist/client/{EodashDatePicker-BIAf1sMT.js → EodashDatePicker-CPlJwEIO.js} +20 -22
- package/dist/client/{EodashItemFilter-DPznh8UB.js → EodashItemFilter-Ydebgbjj.js} +46 -31
- package/dist/client/EodashLayerControl-COhrkNEs.js +1517 -0
- package/dist/client/{EodashLayoutSwitcher-C5qTEffW.js → EodashLayoutSwitcher-pnKhTRZV.js} +4 -4
- package/dist/client/EodashMapBtns-Cj0Fx119.js +301 -0
- package/dist/client/{EodashStacInfo-CSvvF2jI.js → EodashStacInfo-Dadkg_Nj.js} +1 -1
- package/dist/client/EodashTimeSlider-CpoHX0S7.js +53 -0
- package/dist/client/{EodashTools-Cv1SXQ5y.js → EodashTools-UGBG7KC9.js} +10 -7
- package/dist/client/{ExportState-D-iuwaad.js → ExportState-GtJkAqeZ.js} +145 -121
- package/dist/client/{Footer-CyF0zRAk.js → Footer-D3ZPG5c4.js} +1 -1
- package/dist/client/{Header-CgD8jDKU.js → Header-z6AK-wpN.js} +2 -3
- package/dist/client/MobileLayout-BXNsNftb.js +118 -0
- package/dist/client/{PopUp-BsYLvWch.js → PopUp-BbQdjENV.js} +79 -44
- package/dist/client/{ProcessList-C2xsLU2_.js → ProcessList-C6VsdsYI.js} +18 -12
- package/dist/client/{VImg-OHe8YTs2.js → VImg-CxaMSB99.js} +203 -5
- package/dist/client/{VMain-PryTLU4a.js → VMain-Ds7yw0wj.js} +1 -1
- package/dist/client/{VTooltip-DZ0fjpB3.js → VTooltip-Cze6CEVh.js} +2 -3
- package/dist/client/{WidgetsContainer-B9LBadcC.js → WidgetsContainer-D66bj-JJ.js} +1 -1
- package/dist/client/asWebComponent-CWbNRdf9.js +8895 -0
- package/dist/client/{async-DkSu_u2K.js → async-BA7oWCMX.js} +69 -5
- package/dist/client/easing-CH0-9wR8.js +35 -0
- package/dist/client/eo-dash.js +1 -1
- package/dist/client/{VOverlay-yUn7p-Uf.js → forwardRefs-BUfxOIo-.js} +308 -28
- package/dist/client/{handling-CgmFXkW6.js → handling-DlNTtKB-.js} +27 -6
- package/dist/client/{helpers-Dy0Q13tP.js → helpers-CtE0W7iu.js} +595 -278
- package/dist/client/{index-skjhlH8u.js → index-CeEZIjO6.js} +26 -13
- package/dist/client/{index-Ch_HchK3.js → index-CsKbRDeN.js} +238 -77
- package/dist/client/{index-Dqj4tbx2.js → index-D4_NRKrf.js} +2 -2
- package/dist/client/index-DeECc3lV.js +571 -0
- package/dist/client/material-symbols-outlined.woff2 +0 -0
- package/dist/client/material-symbols-rounded.woff2 +0 -0
- package/dist/client/material-symbols-sharp.woff2 +0 -0
- package/dist/client/material-symbols-subset.woff2 +0 -0
- package/dist/client/templates.js +106 -49
- package/dist/client/{transition-C98Yn4Vo.js → transition-Byvp3L6Y.js} +1 -1
- package/dist/node/cli.js +6 -6
- package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +24 -10
- package/dist/types/core/client/eodashSTAC/auth.d.ts +7 -0
- package/dist/types/core/client/eodashSTAC/createLayers.d.ts +15 -3
- package/dist/types/core/client/eodashSTAC/helpers.d.ts +51 -15
- package/dist/types/core/client/plugins/vuetify.d.ts +14 -14
- package/dist/types/core/client/store/actions.d.ts +2 -0
- package/dist/types/core/client/store/stac.d.ts +16 -7
- package/dist/types/core/client/store/states.d.ts +4 -0
- package/dist/types/core/client/types.d.ts +171 -3
- package/dist/types/core/client/utils/bands-editor/arithmetic.d.ts +8 -0
- package/dist/types/core/client/utils/bands-editor/colors.d.ts +15 -0
- package/dist/types/core/client/utils/bands-editor/dom.d.ts +42 -0
- package/dist/types/core/client/utils/bands-editor/index.d.ts +20 -0
- package/dist/types/core/client/utils/bands-editor/rgb.d.ts +15 -0
- package/dist/types/core/client/utils/index.d.ts +1 -1
- package/dist/types/templates/baseConfig.d.ts +87 -1
- package/dist/types/templates/compare.d.ts +0 -25
- package/dist/types/templates/expert.d.ts +17 -21
- package/dist/types/templates/explore.d.ts +67 -0
- package/dist/types/templates/index.d.ts +1 -1
- package/dist/types/templates/{light.d.ts → lite.d.ts} +9 -0
- package/dist/types/widgets/EodashItemCatalog/index.vue.d.ts +21 -0
- package/dist/types/widgets/EodashItemCatalog/methods/filters.d.ts +49 -0
- package/dist/types/widgets/EodashItemCatalog/methods/handlers.d.ts +4 -0
- package/dist/types/widgets/EodashItemCatalog/methods/map.d.ts +12 -0
- package/dist/types/widgets/EodashItemCatalog/types.d.ts +14 -0
- package/dist/types/widgets/{EodashMapBtns.vue.d.ts → EodashMap/EodashMapBtns.vue.d.ts} +6 -0
- package/dist/types/widgets/EodashMap/index.vue.d.ts +114 -0
- package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +1 -1
- package/dist/types/widgets/EodashMap/methods/index.d.ts +1 -1
- package/dist/types/widgets/EodashProcess/methods/async.d.ts +1 -0
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.d.ts +1 -1
- package/dist/types/widgets/EodashTimeSlider.vue.d.ts +7 -0
- package/dist/types/widgets/EodashTools.vue.d.ts +10 -10
- package/dist/types/widgets/ExportState.vue.d.ts +2 -0
- package/package.json +31 -28
- package/templates/baseConfig.js +10 -5
- package/templates/compare.js +2 -22
- package/templates/expert.js +19 -18
- package/templates/explore.js +62 -0
- package/templates/index.js +1 -1
- package/templates/{light.js → lite.js} +11 -2
- package/widgets/EodashDatePicker.vue +15 -18
- package/widgets/EodashItemCatalog/index.vue +161 -0
- package/widgets/EodashItemCatalog/methods/filters.js +216 -0
- package/widgets/EodashItemCatalog/methods/handlers.js +50 -0
- package/widgets/EodashItemCatalog/methods/map.js +144 -0
- package/widgets/EodashItemCatalog/types.ts +15 -0
- package/widgets/EodashItemFilter.vue +35 -28
- package/widgets/EodashLayerControl.vue +10 -6
- package/widgets/EodashLayoutSwitcher.vue +1 -1
- package/widgets/EodashMap/EodashMapBtns.vue +278 -0
- package/widgets/EodashMap/index.vue +263 -38
- package/widgets/EodashMap/methods/create-layers-config.js +9 -6
- package/widgets/EodashMap/methods/index.js +27 -13
- package/widgets/EodashProcess/ProcessList.vue +13 -1
- package/widgets/EodashProcess/index.vue +17 -1
- package/widgets/EodashProcess/methods/async.js +22 -1
- package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +25 -3
- package/widgets/EodashProcess/methods/handling.js +2 -0
- package/widgets/EodashProcess/methods/outputs.js +1 -0
- package/widgets/EodashProcess/methods/utils.js +45 -1
- package/widgets/EodashTimeSlider.vue +40 -0
- package/widgets/EodashTools.vue +7 -3
- package/widgets/ExportState.vue +53 -22
- package/dist/client/EodashLayerControl-Bhxjw4V2.js +0 -154
- package/dist/client/EodashMapBtns-WoGq8MuV.js +0 -173
- package/dist/client/MobileLayout-EKQ_kpSh.js +0 -1226
- package/dist/client/asWebComponent-By_7_JjS.js +0 -19193
- package/dist/client/forwardRefs-BXxrv98s.js +0 -272
- package/dist/client/index-BuhOHXKv.js +0 -199
- package/widgets/EodashMapBtns.vue +0 -155
|
@@ -2,20 +2,28 @@ import { Collection, Item } from "stac-js";
|
|
|
2
2
|
import { toAbsolute } from "stac-js/src/http.js";
|
|
3
3
|
import {
|
|
4
4
|
extractLayerConfig,
|
|
5
|
-
extractLayerDatetime,
|
|
6
5
|
extractRoles,
|
|
6
|
+
fetchApiItems,
|
|
7
7
|
fetchStyle,
|
|
8
|
+
fetchAllStyles,
|
|
8
9
|
findLayer,
|
|
9
10
|
generateFeatures,
|
|
10
11
|
getDatetimeProperty,
|
|
12
|
+
isSTACItem,
|
|
11
13
|
replaceLayer,
|
|
14
|
+
extractLayerLegend,
|
|
15
|
+
extractLayerTimeValues,
|
|
12
16
|
} from "./helpers";
|
|
13
17
|
import {
|
|
14
18
|
getLayers,
|
|
15
19
|
getCompareLayers,
|
|
16
20
|
registerProjection,
|
|
17
21
|
} from "@/store/actions";
|
|
18
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
createLayerFromRender,
|
|
24
|
+
createLayersFromAssets,
|
|
25
|
+
createLayersFromLinks,
|
|
26
|
+
} from "./createLayers";
|
|
19
27
|
import axios from "@/plugins/axios";
|
|
20
28
|
import log from "loglevel";
|
|
21
29
|
import { dataThemesBrands } from "@/utils/states";
|
|
@@ -23,6 +31,10 @@ import { dataThemesBrands } from "@/utils/states";
|
|
|
23
31
|
export class EodashCollection {
|
|
24
32
|
#collectionUrl = "";
|
|
25
33
|
|
|
34
|
+
isAPI = true;
|
|
35
|
+
/** @type {string | null} */
|
|
36
|
+
rasterEndpoint = null;
|
|
37
|
+
|
|
26
38
|
/** @type {import("stac-ts").StacCollection | undefined} */
|
|
27
39
|
#collectionStac;
|
|
28
40
|
|
|
@@ -44,81 +56,87 @@ export class EodashCollection {
|
|
|
44
56
|
return this.#collectionStac;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
59
|
+
/**
|
|
60
|
+
* @param {string} collectionUrl
|
|
61
|
+
* @param {boolean} isAPI
|
|
62
|
+
* @param {string | null} rasterEndpoint
|
|
63
|
+
*/
|
|
64
|
+
constructor(collectionUrl, isAPI = true, rasterEndpoint = null) {
|
|
49
65
|
this.#collectionUrl = collectionUrl;
|
|
66
|
+
this.isAPI = isAPI;
|
|
67
|
+
this.rasterEndpoint = rasterEndpoint;
|
|
50
68
|
}
|
|
51
69
|
|
|
52
70
|
/**
|
|
53
71
|
* @async
|
|
54
|
-
* @param {import('stac-ts').StacLink | Date} [
|
|
55
|
-
* @returns
|
|
72
|
+
* @param {import("stac-ts").StacItem | import('stac-ts').StacLink | Date } [itemOrDate]
|
|
73
|
+
* @returns {Promise<Record<string,any>[]>} layers
|
|
56
74
|
*/
|
|
57
|
-
createLayersJson = async (
|
|
75
|
+
createLayersJson = async (itemOrDate) => {
|
|
58
76
|
/**
|
|
59
|
-
* @type {import("stac-ts").StacLink | undefined}
|
|
77
|
+
* @type {import("stac-ts").StacLink | import("stac-ts").StacItem | undefined}
|
|
60
78
|
**/
|
|
61
|
-
let
|
|
79
|
+
let itemOrItemLink;
|
|
62
80
|
|
|
63
|
-
/**
|
|
64
|
-
* @type {import("stac-ts").StacCollection | import("stac-ts").StacItem | undefined}
|
|
65
|
-
**/
|
|
66
|
-
let stac;
|
|
67
81
|
// TODO get auxiliary layers from collection
|
|
68
82
|
/** @type {Record<string,any>[]} */
|
|
69
83
|
let layersJson = [];
|
|
70
84
|
|
|
71
|
-
// Load collectionstac if not yet initialized
|
|
72
|
-
|
|
85
|
+
// Load collectionstac if not yet initialized // TODO
|
|
86
|
+
await this.fetchCollection();
|
|
73
87
|
|
|
74
|
-
const isObservationPoint =
|
|
88
|
+
const isObservationPoint = this.#collectionStac?.endpointtype === "GeoDB";
|
|
75
89
|
|
|
76
|
-
if (
|
|
90
|
+
if (itemOrDate instanceof Date) {
|
|
77
91
|
// if collectionStac not yet initialized we do it here
|
|
78
|
-
|
|
92
|
+
itemOrItemLink = await this.getItem(itemOrDate);
|
|
79
93
|
} else {
|
|
80
|
-
|
|
94
|
+
itemOrItemLink = itemOrDate;
|
|
81
95
|
}
|
|
82
|
-
let stacItemUrl = "";
|
|
83
|
-
if (itemLink?.href.startsWith("blob:")) {
|
|
84
|
-
stacItemUrl = itemLink.href;
|
|
85
|
-
} else {
|
|
86
|
-
stacItemUrl = itemLink
|
|
87
|
-
? toAbsolute(itemLink.href, this.#collectionUrl)
|
|
88
|
-
: this.#collectionUrl;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
stac = await axios.get(stacItemUrl).then((resp) => resp.data);
|
|
92
|
-
|
|
93
|
-
if (!itemLink) {
|
|
94
|
-
// no specific item was requested; render last item
|
|
95
|
-
this.#collectionStac = new Collection(stac);
|
|
96
|
-
this.selectedItem = this.getItem();
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
let stacItemUrl = "";
|
|
98
|
+
if (isSTACItem(itemOrItemLink)) {
|
|
99
|
+
this.selectedItem = itemOrItemLink;
|
|
100
|
+
stacItemUrl = this.#collectionUrl + `/items/${this.selectedItem.id}`;
|
|
101
|
+
} else if (itemOrItemLink) {
|
|
102
|
+
if (itemOrItemLink?.href?.startsWith("blob:")) {
|
|
103
|
+
stacItemUrl = itemOrItemLink.href;
|
|
104
|
+
// Use native fetch for blob URLs to avoid axios/cache interceptor issues
|
|
105
|
+
this.selectedItem = await fetch(stacItemUrl).then(
|
|
106
|
+
async (resp) => await resp.json(),
|
|
107
|
+
);
|
|
100
108
|
} else {
|
|
109
|
+
stacItemUrl = toAbsolute(itemOrItemLink.href, this.#collectionUrl);
|
|
110
|
+
this.selectedItem = await axios
|
|
111
|
+
.get(stacItemUrl)
|
|
112
|
+
.then((resp) => resp.data);
|
|
113
|
+
}
|
|
114
|
+
} else if (!this.selectedItem) {
|
|
115
|
+
this.selectedItem = await this.getItem();
|
|
116
|
+
if (!this.selectedItem) {
|
|
101
117
|
console.warn(
|
|
102
118
|
"[eodash] the selected collection does not include any items",
|
|
103
119
|
);
|
|
120
|
+
return [];
|
|
121
|
+
} else if (this.selectedItem) {
|
|
122
|
+
// if no specific item was requested, we create layers from the latest item
|
|
123
|
+
return this.createLayersJson(this.selectedItem);
|
|
104
124
|
}
|
|
105
|
-
return [];
|
|
106
|
-
} else {
|
|
107
|
-
// specific item was requested
|
|
108
|
-
const item = new Item(stac);
|
|
109
|
-
this.selectedItem = item;
|
|
110
|
-
const title =
|
|
111
|
-
this.#collectionStac?.title || this.#collectionStac?.id || "";
|
|
112
|
-
layersJson.unshift(
|
|
113
|
-
...(await this.buildJsonArray(
|
|
114
|
-
item,
|
|
115
|
-
stacItemUrl,
|
|
116
|
-
title,
|
|
117
|
-
isObservationPoint,
|
|
118
|
-
)),
|
|
119
|
-
);
|
|
120
|
-
return layersJson;
|
|
121
125
|
}
|
|
126
|
+
|
|
127
|
+
// specific item was requested
|
|
128
|
+
const item = new Item(this.selectedItem);
|
|
129
|
+
this.selectedItem = item;
|
|
130
|
+
const title = this.#collectionStac?.title || this.#collectionStac?.id || "";
|
|
131
|
+
layersJson.unshift(
|
|
132
|
+
...(await this.buildJsonArray(
|
|
133
|
+
item,
|
|
134
|
+
stacItemUrl,
|
|
135
|
+
title,
|
|
136
|
+
isObservationPoint,
|
|
137
|
+
)),
|
|
138
|
+
);
|
|
139
|
+
return layersJson;
|
|
122
140
|
};
|
|
123
141
|
|
|
124
142
|
/**
|
|
@@ -130,6 +148,11 @@ export class EodashCollection {
|
|
|
130
148
|
* @returns {Promise<Record<string,any>[]>} layers
|
|
131
149
|
* */
|
|
132
150
|
async buildJsonArray(item, itemUrl, title, isObservationPoint, itemDatetime) {
|
|
151
|
+
if (!item) {
|
|
152
|
+
console.warn("[eodash] no item provided to buildJsonArray");
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
133
156
|
log.debug(
|
|
134
157
|
"Building JSON array",
|
|
135
158
|
item,
|
|
@@ -160,13 +183,21 @@ export class EodashCollection {
|
|
|
160
183
|
// will try to extract anything it supports but for which we have
|
|
161
184
|
// less control.
|
|
162
185
|
|
|
186
|
+
const rasterformURL = /** @type {string|undefined} */ (
|
|
187
|
+
this.#collectionStac?.["eodash:rasterform"]
|
|
188
|
+
);
|
|
189
|
+
/** @type {import("@/types").EodashRasterJSONForm|undefined} */
|
|
190
|
+
const rasterForm = rasterformURL
|
|
191
|
+
? await axios.get(rasterformURL).then((resp) => resp.data)
|
|
192
|
+
: undefined;
|
|
163
193
|
let { layerConfig, style } = extractLayerConfig(
|
|
164
194
|
this.#collectionStac?.id ?? "",
|
|
165
195
|
await fetchStyle(item, itemUrl),
|
|
196
|
+
rasterForm,
|
|
166
197
|
);
|
|
167
198
|
|
|
168
|
-
const layerDatetime =
|
|
169
|
-
this.getItems(),
|
|
199
|
+
const { layerDatetime, timeControlValues } = extractLayerTimeValues(
|
|
200
|
+
await this.getItems(),
|
|
170
201
|
item.properties?.datetime ??
|
|
171
202
|
item.properties.start_datetime ??
|
|
172
203
|
itemDatetime,
|
|
@@ -179,40 +210,43 @@ export class EodashCollection {
|
|
|
179
210
|
return data;
|
|
180
211
|
}, /** @type {Record<string,import('stac-ts').StacAsset>} */ ({}));
|
|
181
212
|
const isSupported =
|
|
182
|
-
item.links.some((link) => ["wms", "xyz", "wmts"].includes(link.rel)) ||
|
|
213
|
+
item.links.some((link) => ["wms", "xyz", "wmts", "vector-tile"].includes(link.rel)) ||
|
|
183
214
|
Object.keys(dataAssets).length;
|
|
184
215
|
|
|
185
216
|
if (isSupported) {
|
|
186
217
|
// Checking for potential legend asset
|
|
187
|
-
let extraProperties =
|
|
188
|
-
if (this.#collectionStac?.assets?.legend?.href) {
|
|
189
|
-
extraProperties = {
|
|
190
|
-
description: `<div style="width: 100%">
|
|
191
|
-
<img src="${this.#collectionStac.assets.legend.href}" style="max-height:70px; margin-top:-15px; margin-bottom:-20px;" />
|
|
192
|
-
</div>`,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
// Check if collection has eox:colorlegend definition, if yes overwrite legend description
|
|
196
|
-
if (this.#collectionStac && this.#collectionStac["eox:colorlegend"]) {
|
|
197
|
-
extraProperties = {
|
|
198
|
-
layerLegend: this.#collectionStac["eox:colorlegend"],
|
|
199
|
-
};
|
|
200
|
-
}
|
|
218
|
+
let extraProperties = extractLayerLegend(this.#collectionStac);
|
|
201
219
|
extraProperties = {
|
|
202
220
|
...extraProperties,
|
|
203
221
|
...(this.color && { color: this.color }),
|
|
222
|
+
...(timeControlValues && {
|
|
223
|
+
timeControlValues,
|
|
224
|
+
timeControlProperty: "TIME",
|
|
225
|
+
}),
|
|
204
226
|
};
|
|
205
227
|
|
|
206
228
|
const links = await createLayersFromLinks(
|
|
207
229
|
this.#collectionStac?.id ?? "",
|
|
208
230
|
title,
|
|
209
231
|
item,
|
|
232
|
+
itemUrl,
|
|
210
233
|
layerDatetime,
|
|
211
234
|
extraProperties,
|
|
212
235
|
);
|
|
213
236
|
|
|
214
237
|
jsonArray.push(
|
|
215
|
-
...
|
|
238
|
+
...((this.rasterEndpoint &&
|
|
239
|
+
createLayerFromRender(
|
|
240
|
+
this.rasterEndpoint,
|
|
241
|
+
this.#collectionStac,
|
|
242
|
+
item,
|
|
243
|
+
{
|
|
244
|
+
...extraProperties,
|
|
245
|
+
...(layerConfig && { layerConfig }),
|
|
246
|
+
...(layerDatetime && { layerDatetime }),
|
|
247
|
+
},
|
|
248
|
+
)) ||
|
|
249
|
+
[]),
|
|
216
250
|
...(await createLayersFromAssets(
|
|
217
251
|
this.#collectionStac?.id ?? "",
|
|
218
252
|
title || this.#collectionStac?.title || item.id,
|
|
@@ -223,6 +257,8 @@ export class EodashCollection {
|
|
|
223
257
|
layerDatetime,
|
|
224
258
|
extraProperties,
|
|
225
259
|
)),
|
|
260
|
+
// We add the links after the assets so they are layered underneath assets
|
|
261
|
+
...links,
|
|
226
262
|
);
|
|
227
263
|
} else {
|
|
228
264
|
// fallback to STAC
|
|
@@ -251,21 +287,38 @@ export class EodashCollection {
|
|
|
251
287
|
|
|
252
288
|
async fetchCollection() {
|
|
253
289
|
if (!this.#collectionStac) {
|
|
254
|
-
log.debug("Fetching collection file", this.#collectionUrl);
|
|
255
290
|
const col = await axios
|
|
256
291
|
.get(this.#collectionUrl)
|
|
257
292
|
.then((resp) => resp.data);
|
|
258
293
|
this.#collectionStac = new Collection(col);
|
|
294
|
+
log.debug("Fetching collection file", this.#collectionUrl);
|
|
259
295
|
}
|
|
260
296
|
return this.#collectionStac;
|
|
261
297
|
}
|
|
262
298
|
|
|
263
299
|
/**
|
|
264
300
|
* Returns all item links sorted by datetime ascendingly
|
|
301
|
+
* @param {boolean} [fields=false] if true, fetch items from API with only properties
|
|
302
|
+
* @param {boolean} [first] - if true, returns the first page of items only (for API collections)
|
|
303
|
+
* @returns {Promise<import("stac-ts").StacLink[] | import("stac-ts").StacItem[] | undefined>}
|
|
265
304
|
*/
|
|
266
|
-
getItems() {
|
|
267
|
-
const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
|
|
305
|
+
async getItems(fields = false, first = false) {
|
|
268
306
|
const items = this.#collectionStac?.links.filter((i) => i.rel === "item");
|
|
307
|
+
|
|
308
|
+
if (this.isAPI && !items?.length) {
|
|
309
|
+
const itemUrl = this.#collectionUrl + "/items";
|
|
310
|
+
if (fields) {
|
|
311
|
+
return await fetchApiItems(
|
|
312
|
+
itemUrl,
|
|
313
|
+
`fields=properties,-assets,-geometry,-links,-bbox`,
|
|
314
|
+
100,
|
|
315
|
+
first,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
return await fetchApiItems(itemUrl, undefined, 100, first);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
|
|
269
322
|
if (!datetimeProperty) {
|
|
270
323
|
return items;
|
|
271
324
|
}
|
|
@@ -281,14 +334,21 @@ export class EodashCollection {
|
|
|
281
334
|
);
|
|
282
335
|
}
|
|
283
336
|
|
|
284
|
-
getDates() {
|
|
285
|
-
const
|
|
286
|
-
|
|
337
|
+
async getDates() {
|
|
338
|
+
const items = await this.getItems(true, false);
|
|
339
|
+
|
|
340
|
+
const datetimeProperty = getDatetimeProperty(items);
|
|
341
|
+
if (!datetimeProperty || !items?.length) {
|
|
287
342
|
return [];
|
|
288
343
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
344
|
+
|
|
345
|
+
const mapToDates = this.isAPI
|
|
346
|
+
? //@ts-expect-error todo
|
|
347
|
+
(i) =>
|
|
348
|
+
new Date(/** @type {string} */ (i.properties?.[datetimeProperty]))
|
|
349
|
+
: //@ts-expect-error todo
|
|
350
|
+
(i) => new Date(/** @type {string} */ (i[datetimeProperty]));
|
|
351
|
+
return items?.map(mapToDates) || [];
|
|
292
352
|
}
|
|
293
353
|
|
|
294
354
|
async getExtent() {
|
|
@@ -299,38 +359,58 @@ export class EodashCollection {
|
|
|
299
359
|
* Get closest Item Link from a certain date,
|
|
300
360
|
* get the latest if no date provided
|
|
301
361
|
* @param {Date} [date]
|
|
362
|
+
* @return {Promise<import("stac-ts").StacItem | import("stac-ts").StacLink | undefined>} item
|
|
302
363
|
**/
|
|
303
|
-
getItem(date) {
|
|
304
|
-
|
|
364
|
+
async getItem(date) {
|
|
365
|
+
if (!date) {
|
|
366
|
+
return (await this.getItems(false, true))?.[0];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const items = await this.getItems();
|
|
370
|
+
const datetimeProperty = getDatetimeProperty(items);
|
|
305
371
|
if (!datetimeProperty) {
|
|
306
372
|
// in case no datetime property is found, return the first item
|
|
307
|
-
return this.getItems()?.[0];
|
|
373
|
+
return (await this.getItems(false, true))?.[0];
|
|
308
374
|
}
|
|
309
|
-
return
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
375
|
+
return (await this.getItems())?.sort((a, b) => {
|
|
376
|
+
const distanceA = Math.abs(
|
|
377
|
+
new Date(
|
|
378
|
+
/** @type {number} */ (
|
|
379
|
+
//@ts-expect-error TODO
|
|
380
|
+
this.isAPI ? a.properties[datetimeProperty] : a[datetimeProperty]
|
|
381
|
+
),
|
|
382
|
+
).getTime() - date.getTime(),
|
|
383
|
+
);
|
|
384
|
+
const distanceB = Math.abs(
|
|
385
|
+
new Date(
|
|
386
|
+
/** @type {number} */ (
|
|
387
|
+
//@ts-expect-error TODO
|
|
388
|
+
this.isAPI ? b.properties[datetimeProperty] : b[datetimeProperty]
|
|
389
|
+
),
|
|
390
|
+
).getTime() - date.getTime(),
|
|
391
|
+
);
|
|
392
|
+
return distanceA - distanceB;
|
|
393
|
+
})[0];
|
|
322
394
|
}
|
|
323
395
|
|
|
324
396
|
async getToolTipProperties() {
|
|
325
397
|
if (!(this.selectedItem instanceof Item)) {
|
|
326
398
|
return [];
|
|
327
399
|
}
|
|
328
|
-
|
|
400
|
+
// get all style links, which could contribute by tooltip config and aggregate them
|
|
401
|
+
const styles = await fetchAllStyles(
|
|
329
402
|
this.selectedItem,
|
|
330
403
|
`${this.#collectionUrl}/${this.selectedItem.id}`,
|
|
331
404
|
);
|
|
332
|
-
|
|
333
|
-
|
|
405
|
+
// get only unique ids to avoid duplicates
|
|
406
|
+
const aggregatedTooltips = [
|
|
407
|
+
...new Map(
|
|
408
|
+
styles
|
|
409
|
+
.flatMap(style => style.tooltip || [])
|
|
410
|
+
.map(entry => [entry.id, entry])
|
|
411
|
+
).values()
|
|
412
|
+
];
|
|
413
|
+
this.#tooltipProperties = aggregatedTooltips ?? [];
|
|
334
414
|
return this.#tooltipProperties;
|
|
335
415
|
}
|
|
336
416
|
|
|
@@ -342,17 +422,15 @@ export class EodashCollection {
|
|
|
342
422
|
*/
|
|
343
423
|
async updateLayerJson(datetime, layer, map) {
|
|
344
424
|
await this.fetchCollection();
|
|
345
|
-
const datetimeProperty = getDatetimeProperty(
|
|
425
|
+
const datetimeProperty = getDatetimeProperty(
|
|
426
|
+
await this.getItems(true, true),
|
|
427
|
+
);
|
|
346
428
|
if (!datetimeProperty) {
|
|
347
429
|
console.warn("[eodash] no datetime property found in collection");
|
|
348
430
|
return;
|
|
349
431
|
}
|
|
350
432
|
// get the link of the specified date
|
|
351
|
-
const specifiedLink = this.
|
|
352
|
-
(item) =>
|
|
353
|
-
typeof item[datetimeProperty] === "string" &&
|
|
354
|
-
new Date(item[datetimeProperty]).toISOString() === datetime,
|
|
355
|
-
);
|
|
433
|
+
const specifiedLink = await this.getItem(new Date(datetime));
|
|
356
434
|
|
|
357
435
|
if (!specifiedLink) {
|
|
358
436
|
console.warn(
|
|
@@ -361,9 +439,22 @@ export class EodashCollection {
|
|
|
361
439
|
);
|
|
362
440
|
return;
|
|
363
441
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
442
|
+
/** @type {Record<string, any>[]} */
|
|
443
|
+
let newLayers = [];
|
|
444
|
+
if (isSTACItem(specifiedLink)) {
|
|
445
|
+
// if specifiedLink is an item, we create layers from it
|
|
446
|
+
newLayers = await this.buildJsonArray(
|
|
447
|
+
specifiedLink,
|
|
448
|
+
this.#collectionUrl + `/items/${specifiedLink.id}`,
|
|
449
|
+
this.#collectionStac?.title || this.#collectionStac?.id || "",
|
|
450
|
+
this.#collectionStac?.endpointtype === "GeoDB" ||
|
|
451
|
+
!!this.#collectionStac?.locations,
|
|
452
|
+
datetime,
|
|
453
|
+
);
|
|
454
|
+
} else {
|
|
455
|
+
// create json layers from the item
|
|
456
|
+
newLayers = await this.createLayersJson(specifiedLink);
|
|
457
|
+
}
|
|
367
458
|
|
|
368
459
|
let currentLayers = getLayers();
|
|
369
460
|
if (map === "second") {
|
|
@@ -402,10 +493,10 @@ export class EodashCollection {
|
|
|
402
493
|
);
|
|
403
494
|
|
|
404
495
|
return [
|
|
496
|
+
//@ts-expect-error indicator instead of item
|
|
405
497
|
...(await createLayersFromLinks(
|
|
406
498
|
indicator?.id ?? "",
|
|
407
499
|
indicator?.title || indicator.id,
|
|
408
|
-
//@ts-expect-error indicator instead of item
|
|
409
500
|
indicator,
|
|
410
501
|
)),
|
|
411
502
|
...(await createLayersFromAssets(
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic handler for possible authentications schemes as defined in STAC authentication extension.
|
|
3
|
+
* @param {import("@/types").StacAuthItem } item
|
|
4
|
+
* @param {import("@/types").StacAuthLink | import("@/types").StacAuthAsset} linkOrAsset
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
export function handleAuthenticationOfLink(item, linkOrAsset) {
|
|
8
|
+
// browse through all authentication refs on a link to find a first one we support
|
|
9
|
+
for (const authRef of linkOrAsset["auth:refs"] || []) {
|
|
10
|
+
const authSchemes = item["auth:schemes"];
|
|
11
|
+
if (authRef in authSchemes) {
|
|
12
|
+
switch (authSchemes[authRef].type) {
|
|
13
|
+
case "apiKey": {
|
|
14
|
+
//@ts-expect-error TODO
|
|
15
|
+
return handleApiKeyBasedAuth(authSchemes[authRef], linkOrAsset.href);
|
|
16
|
+
}
|
|
17
|
+
// case "signedUrl":
|
|
18
|
+
// case "s3":
|
|
19
|
+
// case "http":
|
|
20
|
+
// case "openIdConnect":
|
|
21
|
+
// case "apiKey":
|
|
22
|
+
// case "oauth2":
|
|
23
|
+
// todo add more handlers when needed
|
|
24
|
+
default:
|
|
25
|
+
console.error(`eodash does not support referenced authentication scheme ${authRef}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return linkOrAsset.href;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generic handler for possible authentications schemes as defined in STAC authentication extension.
|
|
33
|
+
* @param {import("@/types").ApiKeyAuthScheme } schemeDef
|
|
34
|
+
* @param { string } href
|
|
35
|
+
* @returns { string }
|
|
36
|
+
*/
|
|
37
|
+
function handleApiKeyBasedAuth(schemeDef, href) {
|
|
38
|
+
// add token to query parameters of href
|
|
39
|
+
let url = href;
|
|
40
|
+
switch (schemeDef.in) {
|
|
41
|
+
case "query": {
|
|
42
|
+
const apiKey = schemeDef.name;
|
|
43
|
+
const envVar = "EODASH_" + apiKey;
|
|
44
|
+
const envValue = process.env[envVar];
|
|
45
|
+
if (envValue) {
|
|
46
|
+
url = setQueryParam(href, apiKey, envValue);
|
|
47
|
+
} else {
|
|
48
|
+
console.error(`env variable ${envVar} for authentication parameter ${apiKey} not set`);
|
|
49
|
+
}
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
console.error('eodash does not support any referenced handler');
|
|
54
|
+
}
|
|
55
|
+
return url;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Inserts or replaces a query parameter in a URL string (without escaping special characters).
|
|
60
|
+
*
|
|
61
|
+
* @param {string} url - Input URL (may contain special characters)
|
|
62
|
+
* @param {string} key - Query parameter key (e.g. "token", "authCode")
|
|
63
|
+
* @param {string} value - Value to set for the key
|
|
64
|
+
* @returns {string} - Updated URL string
|
|
65
|
+
*/
|
|
66
|
+
function setQueryParam(url, key, value) {
|
|
67
|
+
// Split off any fragment (#something)
|
|
68
|
+
const [base, hash] = url.split("#", 2);
|
|
69
|
+
|
|
70
|
+
// Regex to detect existing key, respecting ? or &
|
|
71
|
+
const pattern = new RegExp(`([?&])${key}=[^&#]*`, "i");
|
|
72
|
+
|
|
73
|
+
if (pattern.test(base)) {
|
|
74
|
+
// Replace existing key=value
|
|
75
|
+
url = base.replace(pattern, `$1${key}=${value}`);
|
|
76
|
+
} else {
|
|
77
|
+
// Append as new key=value
|
|
78
|
+
const joiner = base.includes("?") ? "&" : "?";
|
|
79
|
+
url = `${base}${joiner}${key}=${value}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Reattach fragment if present
|
|
83
|
+
if (hash) url += "#" + hash;
|
|
84
|
+
|
|
85
|
+
return url;
|
|
86
|
+
}
|