@eodash/eodash 5.2.0 → 5.3.1

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.
Files changed (119) hide show
  1. package/core/client/components/DashboardLayout.vue +0 -1
  2. package/core/client/composables/index.js +53 -59
  3. package/core/client/eodashSTAC/EodashCollection.js +196 -94
  4. package/core/client/eodashSTAC/auth.js +86 -0
  5. package/core/client/eodashSTAC/createLayers.js +204 -4
  6. package/core/client/eodashSTAC/helpers.js +254 -62
  7. package/core/client/eodashSTAC/parquet.js +0 -13
  8. package/core/client/eodashSTAC/triggers.js +1 -1
  9. package/core/client/store/actions.js +14 -0
  10. package/core/client/store/stac.js +46 -8
  11. package/core/client/store/states.js +6 -0
  12. package/core/client/types.ts +206 -3
  13. package/core/client/utils/bands-editor/arithmetic.js +144 -0
  14. package/core/client/utils/bands-editor/colors.js +36 -0
  15. package/core/client/utils/bands-editor/dom.js +196 -0
  16. package/core/client/utils/bands-editor/exampleSchema.json +1320 -0
  17. package/core/client/utils/bands-editor/index.js +68 -0
  18. package/core/client/utils/bands-editor/rgb.js +102 -0
  19. package/core/client/utils/index.js +5 -2
  20. package/core/client/views/Dashboard.vue +1 -1
  21. package/core/client/vite-env.d.ts +122 -0
  22. package/dist/client/{DashboardLayout-Dq9Kfe6O.js → DashboardLayout-BAstYnhU.js} +4 -5
  23. package/dist/client/{DynamicWebComponent-DCBMXskE.js → DynamicWebComponent-7v4_DFqP.js} +1 -1
  24. package/dist/client/{EodashDatePicker-DtngxU6s.js → EodashDatePicker-IVHLv9UN.js} +20 -22
  25. package/dist/client/{EodashItemFilter-ClQebJQt.js → EodashItemFilter-BPMpnXjo.js} +46 -31
  26. package/dist/client/EodashLayerControl-CSnQh2tb.js +1517 -0
  27. package/dist/client/{EodashLayoutSwitcher-DQ8SfVDd.js → EodashLayoutSwitcher-CPpGM8Pb.js} +4 -4
  28. package/dist/client/EodashMapBtns-C_jyUJ2x.js +301 -0
  29. package/dist/client/{EodashStacInfo-Dt1nF06x.js → EodashStacInfo-DjuWc0Iz.js} +1 -1
  30. package/dist/client/EodashTimeSlider-CDh9Lf02.js +53 -0
  31. package/dist/client/{EodashTools-DV5ykmWc.js → EodashTools-DSvDUUlL.js} +10 -7
  32. package/dist/client/{ExportState-B6zZQUmE.js → ExportState-BhjxS0jG.js} +145 -120
  33. package/dist/client/{Footer-DNhXs8k6.js → Footer-C3PPcdjv.js} +1 -1
  34. package/dist/client/{Header-BjhN5JY4.js → Header-E5NbT7HE.js} +2 -2
  35. package/dist/client/MobileLayout-DY7OHr1k.js +118 -0
  36. package/dist/client/{PopUp-CgpvNr3o.js → PopUp-CSPXdqKI.js} +79 -43
  37. package/dist/client/{ProcessList-vecpxThi.js → ProcessList-C3HV7G0b.js} +5 -6
  38. package/dist/client/{VImg-CETuikH2.js → VImg-FoXcOnWF.js} +6 -3
  39. package/dist/client/{VMain-Ci9DyaGU.js → VMain-Ck2g1QOG.js} +1 -1
  40. package/dist/client/{VTooltip-J4ac48X7.js → VTooltip-F_1Zcvhp.js} +2 -2
  41. package/dist/client/{WidgetsContainer-CCML4TyV.js → WidgetsContainer-Cq9uZEuN.js} +1 -1
  42. package/dist/client/asWebComponent-DZeEbWG0.js +8895 -0
  43. package/dist/client/{async-B7jIrM53.js → async-Dk79llLt.js} +2 -2
  44. package/dist/client/easing-CH0-9wR8.js +35 -0
  45. package/dist/client/eo-dash.js +1 -1
  46. package/dist/client/{forwardRefs-BQclvjMq.js → forwardRefs-BbvoXHtj.js} +58 -45
  47. package/dist/client/{handling-BS24aG1q.js → handling-DxucYlYh.js} +12 -6
  48. package/dist/client/{helpers-wXK7Ywio.js → helpers-CI_7CUmn.js} +568 -281
  49. package/dist/client/index-BO5uGfUe.js +571 -0
  50. package/dist/client/{index-9KR-G20t.js → index-C13BiO9C.js} +2 -2
  51. package/dist/client/{index-4UCzZi8B.js → index-DcCcdbgR.js} +26 -13
  52. package/dist/client/{index-B2XpdgR6.js → index-KrGHjH-_.js} +63 -36
  53. package/dist/client/templates.js +82 -15
  54. package/dist/client/{transition-yBii4fu6.js → transition-Ctkv90El.js} +1 -1
  55. package/dist/node/cli.js +6 -6
  56. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +24 -10
  57. package/dist/types/core/client/eodashSTAC/auth.d.ts +7 -0
  58. package/dist/types/core/client/eodashSTAC/createLayers.d.ts +15 -3
  59. package/dist/types/core/client/eodashSTAC/helpers.d.ts +47 -16
  60. package/dist/types/core/client/plugins/vuetify.d.ts +14 -14
  61. package/dist/types/core/client/store/actions.d.ts +2 -0
  62. package/dist/types/core/client/store/stac.d.ts +16 -7
  63. package/dist/types/core/client/store/states.d.ts +4 -0
  64. package/dist/types/core/client/types.d.ts +170 -2
  65. package/dist/types/core/client/utils/bands-editor/arithmetic.d.ts +8 -0
  66. package/dist/types/core/client/utils/bands-editor/colors.d.ts +15 -0
  67. package/dist/types/core/client/utils/bands-editor/dom.d.ts +42 -0
  68. package/dist/types/core/client/utils/bands-editor/index.d.ts +20 -0
  69. package/dist/types/core/client/utils/bands-editor/rgb.d.ts +15 -0
  70. package/dist/types/core/client/utils/index.d.ts +1 -1
  71. package/dist/types/templates/baseConfig.d.ts +87 -1
  72. package/dist/types/templates/expert.d.ts +6 -6
  73. package/dist/types/templates/explore.d.ts +67 -0
  74. package/dist/types/templates/index.d.ts +1 -1
  75. package/dist/types/templates/{light.d.ts → lite.d.ts} +5 -5
  76. package/dist/types/widgets/EodashItemCatalog/index.vue.d.ts +21 -0
  77. package/dist/types/widgets/EodashItemCatalog/methods/filters.d.ts +49 -0
  78. package/dist/types/widgets/EodashItemCatalog/methods/handlers.d.ts +4 -0
  79. package/dist/types/widgets/EodashItemCatalog/methods/map.d.ts +12 -0
  80. package/dist/types/widgets/EodashItemCatalog/types.d.ts +14 -0
  81. package/dist/types/widgets/EodashMap/EodashMapBtns.vue.d.ts +2 -0
  82. package/dist/types/widgets/EodashMap/index.vue.d.ts +108 -2
  83. package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +1 -1
  84. package/dist/types/widgets/EodashMap/methods/index.d.ts +1 -1
  85. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.d.ts +1 -1
  86. package/dist/types/widgets/EodashTimeSlider.vue.d.ts +7 -0
  87. package/dist/types/widgets/EodashTools.vue.d.ts +10 -10
  88. package/dist/types/widgets/ExportState.vue.d.ts +2 -0
  89. package/package.json +28 -27
  90. package/templates/baseConfig.js +10 -5
  91. package/templates/compare.js +2 -2
  92. package/templates/expert.js +5 -5
  93. package/templates/explore.js +62 -0
  94. package/templates/index.js +1 -1
  95. package/templates/{light.js → lite.js} +1 -1
  96. package/widgets/EodashDatePicker.vue +15 -18
  97. package/widgets/EodashItemCatalog/index.vue +161 -0
  98. package/widgets/EodashItemCatalog/methods/filters.js +216 -0
  99. package/widgets/EodashItemCatalog/methods/handlers.js +50 -0
  100. package/widgets/EodashItemCatalog/methods/map.js +144 -0
  101. package/widgets/EodashItemCatalog/types.ts +15 -0
  102. package/widgets/EodashItemFilter.vue +35 -28
  103. package/widgets/EodashLayerControl.vue +10 -6
  104. package/widgets/EodashLayoutSwitcher.vue +1 -1
  105. package/widgets/EodashMap/EodashMapBtns.vue +18 -9
  106. package/widgets/EodashMap/index.vue +22 -12
  107. package/widgets/EodashMap/methods/create-layers-config.js +9 -6
  108. package/widgets/EodashMap/methods/index.js +27 -13
  109. package/widgets/EodashProcess/index.vue +17 -1
  110. package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +9 -3
  111. package/widgets/EodashProcess/methods/handling.js +2 -0
  112. package/widgets/EodashProcess/methods/outputs.js +1 -0
  113. package/widgets/EodashTimeSlider.vue +40 -0
  114. package/widgets/EodashTools.vue +7 -3
  115. package/widgets/ExportState.vue +53 -22
  116. package/dist/client/EodashLayerControl-BLBds28C.js +0 -154
  117. package/dist/client/EodashMapBtns-B89_YBDw.js +0 -326
  118. package/dist/client/MobileLayout-JelB6w1G.js +0 -118
  119. package/dist/client/asWebComponent-ZyEzWOOf.js +0 -19092
@@ -3,7 +3,6 @@
3
3
  <eox-layout
4
4
  :mediaBreakpoints="[0, 960, 1920]"
5
5
  :gap="gap"
6
- class="layout-container"
7
6
  :style="layoutStyle"
8
7
  >
9
8
  <eox-layout-item
@@ -22,6 +22,7 @@ import { setCollectionsPalette } from "@/utils";
22
22
  import mustache from "mustache";
23
23
  import { toAbsolute } from "stac-js/src/http.js";
24
24
  import axios from "@/plugins/axios";
25
+ import { storeToRefs } from "pinia";
25
26
 
26
27
  /**
27
28
  /** @type {import('@/types').Eodash | null}*/
@@ -57,68 +58,60 @@ export function useEodash() {
57
58
  }
58
59
 
59
60
  /**
60
- * Creates an absolute URL from a relative link and assignes it to `currentUrl`
61
- *
62
- * @param {string} [rel=''] Default is `''`
63
- * @param {string} [base=eodash.stacEndpoint] - Base URL, default value is the
64
- * root stac catalog. Default is `eodash.stacEndpoint`
65
- * @returns {import("vue").Ref<string>} - Returns `currentUrl`
66
- * @see {@link '@/store/states.js'}
61
+ * @param {import("vue").Ref<string>} absoluteUrl
62
+ * @returns
67
63
  */
68
- export const useAbsoluteUrl = (
69
- rel = "",
70
- base = inject(eodashKey)?.stacEndpoint,
71
- ) => {
72
- if (!rel || rel.includes("http") || !base) {
73
- currentUrl.value = rel;
74
- return currentUrl;
75
- }
76
-
77
- const st = base.split("/");
78
- const arr = rel.split("/");
79
- st.pop();
80
-
81
- for (let i = 0; i < arr.length; i++) {
82
- if (arr[i] == ".") continue;
83
- if (arr[i] == "..") st.pop();
84
- else st.push(arr[i]);
85
- }
86
-
87
- currentUrl.value = st.join("/");
88
- return currentUrl;
89
- };
64
+ const createUseAbsoluteUrl = (absoluteUrl) => {
65
+ /**
66
+ * Creates an absolute URL from a relative link and assignes it to `currentUrl`
67
+ *
68
+ * @param {string} [rel=''] Default is `''`
69
+ * @param {string} [base=eodash.stacEndpoint] - Base URL, default value is the
70
+ * root stac catalog. Default is `eodash.stacEndpoint`
71
+ * @returns {import("vue").Ref<string>} - Returns `currentUrl`
72
+ * @see {@link '@/store/states.js'}
73
+ */
74
+ return (rel = "", base) => {
75
+ const { stacEndpoint, isApi } = storeToRefs(useSTAcStore());
76
+ if (!base) {
77
+ base = stacEndpoint.value ?? undefined;
78
+ if (!base) {
79
+ console.warn(
80
+ "[eodash] No base URL provided for absolute URL construction.",
81
+ );
82
+ return absoluteUrl;
83
+ }
84
+ }
85
+ if (isApi.value) {
86
+ absoluteUrl.value = base + `/collections/${rel}`;
87
+ return absoluteUrl;
88
+ }
90
89
 
91
- /**
92
- * Use the absolute compare URL from a relative link
93
- *
94
- * @param {string} [rel=''] Default is `''`
95
- * @param {string} [base=eodash.stacEndpoint] - Base URL, default value is the
96
- * root stac catalog. Default is `eodash.stacEndpoint`
97
- * @returns {import("vue").Ref<string>} - Returns `currentUrl`
98
- * @see {@link '@/store/states.js'}
99
- */
100
- export const useCompareAbsoluteUrl = (
101
- rel = "",
102
- base = inject(eodashKey)?.stacEndpoint,
103
- ) => {
104
- if (!rel || rel.includes("http") || !base) {
105
- currentCompareUrl.value = rel;
106
- return currentCompareUrl;
107
- }
90
+ if (rel.includes("http")) {
91
+ absoluteUrl.value = rel;
92
+ return absoluteUrl;
93
+ }
94
+ if (!rel) {
95
+ absoluteUrl.value = base;
96
+ return absoluteUrl;
97
+ }
108
98
 
109
- const st = base.split("/");
110
- const arr = rel.split("/");
111
- st.pop();
99
+ const st = base.split("/");
100
+ const arr = rel.split("/");
101
+ st.pop();
112
102
 
113
- for (let i = 0; i < arr.length; i++) {
114
- if (arr[i] == ".") continue;
115
- if (arr[i] == "..") st.pop();
116
- else st.push(arr[i]);
117
- }
103
+ for (let i = 0; i < arr.length; i++) {
104
+ if (arr[i] == ".") continue;
105
+ if (arr[i] == "..") st.pop();
106
+ else st.push(arr[i]);
107
+ }
118
108
 
119
- currentCompareUrl.value = st.join("/");
120
- return currentCompareUrl;
109
+ absoluteUrl.value = st.join("/");
110
+ return absoluteUrl;
111
+ };
121
112
  };
113
+ export const useAbsoluteUrl = createUseAbsoluteUrl(currentUrl);
114
+ export const useCompareAbsoluteUrl = createUseAbsoluteUrl(currentCompareUrl);
122
115
 
123
116
  /**
124
117
  * Updates an existing Vuetify theme. updates only the values provided in the
@@ -178,7 +171,6 @@ export const useURLSearchParametersSync = () => {
178
171
  }
179
172
  case "indicator": {
180
173
  log.debug("Found indicator key in url");
181
- const eodash = inject(eodashKey);
182
174
  const match = store.stac?.find(
183
175
  (link) => useGetSubCodeId(link) == value,
184
176
  );
@@ -187,7 +179,7 @@ export const useURLSearchParametersSync = () => {
187
179
  if (searchParams.has("poi")) {
188
180
  const indicatorUrl = toAbsolute(
189
181
  match.href,
190
- eodash?.stacEndpoint ?? "",
182
+ store.stacEndpoint ?? "",
191
183
  );
192
184
  // fetch indicator stac collection without rendering it
193
185
  /** @type {import("stac-ts").StacCollection} */
@@ -224,7 +216,9 @@ export const useURLSearchParametersSync = () => {
224
216
  await store.loadSelectedSTAC(poiAbsoluteUrl, true);
225
217
  }
226
218
  } else {
227
- await store.loadSelectedSTAC(match.href);
219
+ await store.loadSelectedSTAC(
220
+ /** @type {string} */ (store.isApi ? match.id : match.href),
221
+ );
228
222
  }
229
223
  }
230
224
  break;
@@ -2,21 +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,
12
14
  extractLayerLegend,
15
+ extractLayerTimeValues,
13
16
  } from "./helpers";
14
17
  import {
15
18
  getLayers,
16
19
  getCompareLayers,
17
20
  registerProjection,
18
21
  } from "@/store/actions";
19
- import { createLayersFromAssets, createLayersFromLinks } from "./createLayers";
22
+ import {
23
+ createLayerFromRender,
24
+ createLayersFromAssets,
25
+ createLayersFromLinks,
26
+ } from "./createLayers";
20
27
  import axios from "@/plugins/axios";
21
28
  import log from "loglevel";
22
29
  import { dataThemesBrands } from "@/utils/states";
@@ -24,6 +31,10 @@ import { dataThemesBrands } from "@/utils/states";
24
31
  export class EodashCollection {
25
32
  #collectionUrl = "";
26
33
 
34
+ isAPI = true;
35
+ /** @type {string | null} */
36
+ rasterEndpoint = null;
37
+
27
38
  /** @type {import("stac-ts").StacCollection | undefined} */
28
39
  #collectionStac;
29
40
 
@@ -45,81 +56,87 @@ export class EodashCollection {
45
56
  return this.#collectionStac;
46
57
  }
47
58
 
48
- /** @param {string} collectionUrl */
49
- constructor(collectionUrl) {
59
+ /**
60
+ * @param {string} collectionUrl
61
+ * @param {boolean} isAPI
62
+ * @param {string | null} rasterEndpoint
63
+ */
64
+ constructor(collectionUrl, isAPI = true, rasterEndpoint = null) {
50
65
  this.#collectionUrl = collectionUrl;
66
+ this.isAPI = isAPI;
67
+ this.rasterEndpoint = rasterEndpoint;
51
68
  }
52
69
 
53
70
  /**
54
71
  * @async
55
- * @param {import('stac-ts').StacLink | Date} [linkOrDate]
56
- * @returns
72
+ * @param {import("stac-ts").StacItem | import('stac-ts').StacLink | Date } [itemOrDate]
73
+ * @returns {Promise<Record<string,any>[]>} layers
57
74
  */
58
- createLayersJson = async (linkOrDate) => {
75
+ createLayersJson = async (itemOrDate) => {
59
76
  /**
60
- * @type {import("stac-ts").StacLink | undefined}
77
+ * @type {import("stac-ts").StacLink | import("stac-ts").StacItem | undefined}
61
78
  **/
62
- let itemLink;
79
+ let itemOrItemLink;
63
80
 
64
- /**
65
- * @type {import("stac-ts").StacCollection | import("stac-ts").StacItem | undefined}
66
- **/
67
- let stac;
68
81
  // TODO get auxiliary layers from collection
69
82
  /** @type {Record<string,any>[]} */
70
83
  let layersJson = [];
71
84
 
72
- // Load collectionstac if not yet initialized
73
- stac = await this.fetchCollection();
85
+ // Load collectionstac if not yet initialized // TODO
86
+ await this.fetchCollection();
74
87
 
75
- const isObservationPoint = stac?.endpointtype === "GeoDB";
88
+ const isObservationPoint = this.#collectionStac?.endpointtype === "GeoDB";
76
89
 
77
- if (linkOrDate instanceof Date) {
90
+ if (itemOrDate instanceof Date) {
78
91
  // if collectionStac not yet initialized we do it here
79
- itemLink = this.getItem(linkOrDate);
92
+ itemOrItemLink = await this.getItem(itemOrDate);
80
93
  } else {
81
- itemLink = linkOrDate;
94
+ itemOrItemLink = itemOrDate;
82
95
  }
83
- let stacItemUrl = "";
84
- if (itemLink?.href.startsWith("blob:")) {
85
- stacItemUrl = itemLink.href;
86
- } else {
87
- stacItemUrl = itemLink
88
- ? toAbsolute(itemLink.href, this.#collectionUrl)
89
- : this.#collectionUrl;
90
- }
91
-
92
- stac = await axios.get(stacItemUrl).then((resp) => resp.data);
93
96
 
94
- if (!itemLink) {
95
- // no specific item was requested; render last item
96
- this.#collectionStac = new Collection(stac);
97
- this.selectedItem = this.getItem();
98
-
99
- if (this.selectedItem) {
100
- layersJson = await this.createLayersJson(this.selectedItem);
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
+ );
101
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) {
102
117
  console.warn(
103
118
  "[eodash] the selected collection does not include any items",
104
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);
105
124
  }
106
- return [];
107
- } else {
108
- // specific item was requested
109
- const item = new Item(stac);
110
- this.selectedItem = item;
111
- const title =
112
- this.#collectionStac?.title || this.#collectionStac?.id || "";
113
- layersJson.unshift(
114
- ...(await this.buildJsonArray(
115
- item,
116
- stacItemUrl,
117
- title,
118
- isObservationPoint,
119
- )),
120
- );
121
- return layersJson;
122
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;
123
140
  };
124
141
 
125
142
  /**
@@ -131,6 +148,11 @@ export class EodashCollection {
131
148
  * @returns {Promise<Record<string,any>[]>} layers
132
149
  * */
133
150
  async buildJsonArray(item, itemUrl, title, isObservationPoint, itemDatetime) {
151
+ if (!item) {
152
+ console.warn("[eodash] no item provided to buildJsonArray");
153
+ return [];
154
+ }
155
+
134
156
  log.debug(
135
157
  "Building JSON array",
136
158
  item,
@@ -161,13 +183,21 @@ export class EodashCollection {
161
183
  // will try to extract anything it supports but for which we have
162
184
  // less control.
163
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;
164
193
  let { layerConfig, style } = extractLayerConfig(
165
194
  this.#collectionStac?.id ?? "",
166
195
  await fetchStyle(item, itemUrl),
196
+ rasterForm,
167
197
  );
168
198
 
169
- const layerDatetime = extractLayerDatetime(
170
- this.getItems(),
199
+ const { layerDatetime, timeControlValues } = extractLayerTimeValues(
200
+ await this.getItems(),
171
201
  item.properties?.datetime ??
172
202
  item.properties.start_datetime ??
173
203
  itemDatetime,
@@ -180,7 +210,7 @@ export class EodashCollection {
180
210
  return data;
181
211
  }, /** @type {Record<string,import('stac-ts').StacAsset>} */ ({}));
182
212
  const isSupported =
183
- item.links.some((link) => ["wms", "xyz", "wmts"].includes(link.rel)) ||
213
+ item.links.some((link) => ["wms", "xyz", "wmts", "vector-tile"].includes(link.rel)) ||
184
214
  Object.keys(dataAssets).length;
185
215
 
186
216
  if (isSupported) {
@@ -189,17 +219,34 @@ export class EodashCollection {
189
219
  extraProperties = {
190
220
  ...extraProperties,
191
221
  ...(this.color && { color: this.color }),
222
+ ...(timeControlValues && {
223
+ timeControlValues,
224
+ timeControlProperty: "TIME",
225
+ }),
192
226
  };
193
227
 
194
228
  const links = await createLayersFromLinks(
195
229
  this.#collectionStac?.id ?? "",
196
230
  title,
197
231
  item,
232
+ itemUrl,
198
233
  layerDatetime,
199
234
  extraProperties,
200
235
  );
201
236
 
202
237
  jsonArray.push(
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
+ []),
203
250
  ...(await createLayersFromAssets(
204
251
  this.#collectionStac?.id ?? "",
205
252
  title || this.#collectionStac?.title || item.id,
@@ -210,8 +257,8 @@ export class EodashCollection {
210
257
  layerDatetime,
211
258
  extraProperties,
212
259
  )),
213
- ...links,
214
260
  // We add the links after the assets so they are layered underneath assets
261
+ ...links,
215
262
  );
216
263
  } else {
217
264
  // fallback to STAC
@@ -240,21 +287,38 @@ export class EodashCollection {
240
287
 
241
288
  async fetchCollection() {
242
289
  if (!this.#collectionStac) {
243
- log.debug("Fetching collection file", this.#collectionUrl);
244
290
  const col = await axios
245
291
  .get(this.#collectionUrl)
246
292
  .then((resp) => resp.data);
247
293
  this.#collectionStac = new Collection(col);
294
+ log.debug("Fetching collection file", this.#collectionUrl);
248
295
  }
249
296
  return this.#collectionStac;
250
297
  }
251
298
 
252
299
  /**
253
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>}
254
304
  */
255
- getItems() {
256
- const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
305
+ async getItems(fields = false, first = false) {
257
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);
258
322
  if (!datetimeProperty) {
259
323
  return items;
260
324
  }
@@ -270,14 +334,21 @@ export class EodashCollection {
270
334
  );
271
335
  }
272
336
 
273
- getDates() {
274
- const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
275
- if (!datetimeProperty) {
337
+ async getDates() {
338
+ const items = await this.getItems(true, false);
339
+
340
+ const datetimeProperty = getDatetimeProperty(items);
341
+ if (!datetimeProperty || !items?.length) {
276
342
  return [];
277
343
  }
278
- return this.getItems()?.map(
279
- (i) => new Date(/** @type {number} */ (i[datetimeProperty])),
280
- );
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) || [];
281
352
  }
282
353
 
283
354
  async getExtent() {
@@ -288,38 +359,58 @@ export class EodashCollection {
288
359
  * Get closest Item Link from a certain date,
289
360
  * get the latest if no date provided
290
361
  * @param {Date} [date]
362
+ * @return {Promise<import("stac-ts").StacItem | import("stac-ts").StacLink | undefined>} item
291
363
  **/
292
- getItem(date) {
293
- const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
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);
294
371
  if (!datetimeProperty) {
295
372
  // in case no datetime property is found, return the first item
296
- return this.getItems()?.[0];
373
+ return (await this.getItems(false, true))?.[0];
297
374
  }
298
- return date
299
- ? this.getItems()?.sort((a, b) => {
300
- const distanceA = Math.abs(
301
- new Date(/** @type {number} */ (a[datetimeProperty])).getTime() -
302
- date.getTime(),
303
- );
304
- const distanceB = Math.abs(
305
- new Date(/** @type {number} */ (b[datetimeProperty])).getTime() -
306
- date.getTime(),
307
- );
308
- return distanceA - distanceB;
309
- })[0]
310
- : this.getItems()?.at(-1);
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];
311
394
  }
312
395
 
313
396
  async getToolTipProperties() {
314
397
  if (!(this.selectedItem instanceof Item)) {
315
398
  return [];
316
399
  }
317
- let styles = await fetchStyle(
400
+ // get all style links, which could contribute by tooltip config and aggregate them
401
+ const styles = await fetchAllStyles(
318
402
  this.selectedItem,
319
403
  `${this.#collectionUrl}/${this.selectedItem.id}`,
320
404
  );
321
- const { tooltip } = styles || { tooltip: [] };
322
- this.#tooltipProperties = tooltip ?? [];
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 ?? [];
323
414
  return this.#tooltipProperties;
324
415
  }
325
416
 
@@ -331,17 +422,15 @@ export class EodashCollection {
331
422
  */
332
423
  async updateLayerJson(datetime, layer, map) {
333
424
  await this.fetchCollection();
334
- const datetimeProperty = getDatetimeProperty(this.#collectionStac?.links);
425
+ const datetimeProperty = getDatetimeProperty(
426
+ await this.getItems(true, true),
427
+ );
335
428
  if (!datetimeProperty) {
336
429
  console.warn("[eodash] no datetime property found in collection");
337
430
  return;
338
431
  }
339
432
  // get the link of the specified date
340
- const specifiedLink = this.getItems()?.find(
341
- (item) =>
342
- typeof item[datetimeProperty] === "string" &&
343
- new Date(item[datetimeProperty]).toISOString() === datetime,
344
- );
433
+ const specifiedLink = await this.getItem(new Date(datetime));
345
434
 
346
435
  if (!specifiedLink) {
347
436
  console.warn(
@@ -350,9 +439,22 @@ export class EodashCollection {
350
439
  );
351
440
  return;
352
441
  }
353
-
354
- // create json layers from the item
355
- const newLayers = await this.createLayersJson(specifiedLink);
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
+ }
356
458
 
357
459
  let currentLayers = getLayers();
358
460
  if (map === "second") {
@@ -391,10 +493,10 @@ export class EodashCollection {
391
493
  );
392
494
 
393
495
  return [
496
+ //@ts-expect-error indicator instead of item
394
497
  ...(await createLayersFromLinks(
395
498
  indicator?.id ?? "",
396
499
  indicator?.title || indicator.id,
397
- //@ts-expect-error indicator instead of item
398
500
  indicator,
399
501
  )),
400
502
  ...(await createLayersFromAssets(