@eodash/eodash 5.0.0-alpha.2.1 → 5.0.0-alpha.2.10

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 (136) hide show
  1. package/README.md +36 -3
  2. package/core/client/App.vue +26 -0
  3. package/core/client/SuspensedDashboard.ce.vue +105 -0
  4. package/core/client/asWebComponent.d.ts +23 -0
  5. package/core/client/asWebComponent.js +12 -0
  6. package/core/client/components/DashboardLayout.vue +77 -0
  7. package/core/client/components/DynamicWebComponent.vue +68 -0
  8. package/core/client/components/ErrorAlert.vue +36 -0
  9. package/core/{components → client/components}/Footer.vue +34 -15
  10. package/core/client/components/Header.vue +19 -0
  11. package/core/client/components/IframeWrapper.vue +11 -0
  12. package/core/client/components/Loading.vue +37 -0
  13. package/core/client/components/MobileLayout.vue +109 -0
  14. package/core/client/composables/DefineEodash.js +67 -0
  15. package/core/client/composables/DefineWidgets.js +161 -0
  16. package/core/client/composables/index.js +136 -0
  17. package/core/client/eodash.js +136 -0
  18. package/core/client/main.js +2 -0
  19. package/core/client/plugins/index.js +20 -0
  20. package/core/client/plugins/vuetify.js +35 -0
  21. package/core/client/render.js +12 -0
  22. package/core/client/store/Actions.js +62 -0
  23. package/core/client/store/States.js +21 -0
  24. package/core/client/store/index.js +20 -0
  25. package/core/client/store/stac.js +81 -0
  26. package/core/client/types.d.ts +287 -0
  27. package/core/client/utils/eodashSTAC.js +337 -0
  28. package/core/client/utils/helpers.js +172 -0
  29. package/core/client/utils/index.js +51 -0
  30. package/core/{utils → client/utils}/keys.js +2 -2
  31. package/core/client/views/Dashboard.vue +116 -0
  32. package/core/client/vite-env.d.ts +39 -0
  33. package/dist/client/DashboardLayout-C_3q8Y10.js +156 -0
  34. package/dist/{DynamicWebComponent-BrHVTesn.js → client/DynamicWebComponent-IiTTLBt-.js} +11 -11
  35. package/dist/client/EodashDatePicker-DgC1lccp.js +252 -0
  36. package/dist/{eox-itemfilter-DcQkRD2l.js → client/EodashItemFilter-DoWZGe6r.js} +1515 -1381
  37. package/dist/client/EodashMap-C96D3LLv.js +114352 -0
  38. package/dist/client/EodashMapBtns-DDtzV94u.js +50 -0
  39. package/dist/client/ExportState-CduS2mFs.js +558 -0
  40. package/dist/client/Footer-DHQcutCv.js +115 -0
  41. package/dist/client/Header-DC0y7rLK.js +350 -0
  42. package/dist/{IframeWrapper-Dd9zrX9s.js → client/IframeWrapper-BK-10FbS.js} +4 -4
  43. package/dist/client/MobileLayout-BpLoMY4i.js +945 -0
  44. package/dist/client/PopUp-CNMCWL0z.js +300 -0
  45. package/dist/client/VImg-DT7eb8V-.js +291 -0
  46. package/dist/client/VMain-OenWyy46.js +39 -0
  47. package/dist/client/VOverlay-x3UXpKhr.js +972 -0
  48. package/dist/{WidgetsContainer-DxfCu0I3.js → client/WidgetsContainer-qMUwtN0W.js} +24 -17
  49. package/dist/client/asWebComponent-DQrnLsI2.js +20404 -0
  50. package/dist/{basedecoder-Qm25PwVp-CHo5Pomv.js → client/basedecoder-DHcBySSe-BmCFNFnw.js} +5 -6
  51. package/dist/{decoder-kAoyGIq9-BBR5CgzS.js → client/decoder-Cth6J7EK-CtUoHA6r.js} +1 -1
  52. package/dist/client/deflate-BXt-9JA_-CWfClgpK.js +10 -0
  53. package/dist/client/eo-dash.js +6 -0
  54. package/dist/client/eox-jsonform-DCErgjhw.js +17515 -0
  55. package/dist/client/eox-layercontrol-D0Ht7Mag.js +21298 -0
  56. package/dist/client/eox-stacinfo-l7ALSV90.js +13969 -0
  57. package/dist/client/forwardRefs-CpNjL95t.js +185 -0
  58. package/dist/client/helpers-KCSgmfim.js +1417 -0
  59. package/dist/{index-DTkOfh2g.js → client/index-DopVrUzM.js} +22 -21
  60. package/dist/{jpeg-DNfUpLwy-Fjan-04T.js → client/jpeg-BAgeD1d3-oeHbFPUL.js} +5 -6
  61. package/dist/{lerc-C9VL9kri-cIdbW0sg.js → client/lerc-BgbQqdFI-D986ErVw.js} +37 -39
  62. package/dist/{lzw-BOMhmEDy-Dboc93VO.js → client/lzw-LAGDNbSC-DkP96qO9.js} +1 -1
  63. package/dist/{packbits-DaUD6MLm-Bu1PoTGa.js → client/packbits-BlDR4Kj5-C66n1-zr.js} +1 -1
  64. package/dist/{pako.esm-C3kYPGGQ-BMki8cQY.js → client/pako.esm-CB1uQYY0-DB0PYm1P.js} +6 -12
  65. package/dist/{raw-CcGKjn8q-DFOt-i8n.js → client/raw-CMGvRjfu-BRi6E4i1.js} +1 -1
  66. package/dist/{ssrBoot-D-b4-M19.js → client/ssrBoot-DkjdOWvj.js} +1 -1
  67. package/dist/client/style.css +5 -0
  68. package/dist/client/transition-BtJHh7JK.js +34 -0
  69. package/dist/{webfontloader-CyOFAuFB.js → client/webfontloader-qotgY98I.js} +56 -92
  70. package/dist/{webimage-D2c098k3-DLj1LQxB.js → client/webimage-BM_pbLN3-L2cGWK5l.js} +1 -1
  71. package/dist/node/cli.js +20 -0
  72. package/dist/node/main.js +2 -0
  73. package/dist/node/types.d.ts +47 -0
  74. package/package.json +54 -51
  75. package/widgets/EodashDatePicker.vue +145 -40
  76. package/widgets/EodashItemFilter.vue +73 -38
  77. package/widgets/EodashMap.vue +210 -37
  78. package/widgets/EodashMapBtns.vue +50 -0
  79. package/widgets/ExportState.vue +112 -0
  80. package/widgets/PopUp.vue +40 -0
  81. package/widgets/WidgetsContainer.vue +47 -27
  82. package/bin/app.js +0 -22
  83. package/bin/cli.js +0 -62
  84. package/bin/main.js +0 -9
  85. package/bin/serverConfig.js +0 -165
  86. package/bin/types.d.ts +0 -52
  87. package/bin/utils.js +0 -103
  88. package/core/App.vue +0 -19
  89. package/core/SuspensedDashboard.ce.vue +0 -65
  90. package/core/asWebComponent.d.ts +0 -18
  91. package/core/asWebComponent.js +0 -12
  92. package/core/components/DashboardLayout.vue +0 -44
  93. package/core/components/DynamicWebComponent.vue +0 -68
  94. package/core/components/Header.vue +0 -14
  95. package/core/components/IframeWrapper.vue +0 -11
  96. package/core/components/Loading.vue +0 -27
  97. package/core/components/MobileLayout.vue +0 -49
  98. package/core/composables/DefineEodash.js +0 -57
  99. package/core/composables/DefineWidgets.js +0 -129
  100. package/core/composables/index.js +0 -219
  101. package/core/eodash.js +0 -100
  102. package/core/main.js +0 -2
  103. package/core/plugins/index.js +0 -18
  104. package/core/plugins/vuetify.js +0 -30
  105. package/core/render.js +0 -13
  106. package/core/store/Actions.js +0 -0
  107. package/core/store/States.js +0 -21
  108. package/core/store/index.js +0 -17
  109. package/core/store/stac.js +0 -63
  110. package/core/types.d.ts +0 -356
  111. package/core/utils/eodashSTAC.js +0 -164
  112. package/core/utils/helpers.js +0 -40
  113. package/core/utils/index.js +0 -28
  114. package/core/views/Dashboard.vue +0 -59
  115. package/core/vite-env.d.ts +0 -31
  116. package/dist/DashboardLayout-Dp8AnYD9.js +0 -141
  117. package/dist/EodashDatePicker-D_udZ26j.js +0 -1645
  118. package/dist/EodashItemFilter-BLAGx2UD.js +0 -51
  119. package/dist/EodashMap-Bxl_aqY2.js +0 -53405
  120. package/dist/Footer-AohCH8U7.js +0 -118
  121. package/dist/Header-DC50S6GR.js +0 -609
  122. package/dist/MobileLayout-CgToA7Gp.js +0 -523
  123. package/dist/VBtn-Bz7ruRUg.js +0 -1106
  124. package/dist/VMain-BHfWJU2j.js +0 -35
  125. package/dist/asWebComponent-C8rb3b1D.js +0 -11323
  126. package/dist/color-DpYEub1f.js +0 -115
  127. package/dist/deflate-Be2Arps5-hDqMz3RA.js +0 -10
  128. package/dist/dimensions-CJaGeSrj.js +0 -53
  129. package/dist/eo-dash.js +0 -6
  130. package/dist/eox-map-BJ9SIixs.js +0 -36205
  131. package/dist/eox-stacinfo-B-YrT7Ug.js +0 -13698
  132. package/dist/forwardRefs-Bxeu9Obx.js +0 -142
  133. package/dist/index-Sa2Vg_gx.js +0 -65
  134. package/dist/style.css +0 -5
  135. /package/dist/{.gitkeep → client/.gitkeep} +0 -0
  136. /package/dist/{_commonjsHelpers-DaMA6jEr.js → client/_commonjsHelpers-DaMA6jEr.js} +0 -0
@@ -0,0 +1,81 @@
1
+ import { defineStore } from "pinia";
2
+ import { inject, ref } from "vue";
3
+ import axios from "axios";
4
+ import { useAbsoluteUrl } from "@/composables/index";
5
+ import { eodashKey } from "@/utils/keys";
6
+ import { indicator } from "@/store/States";
7
+
8
+ export const useSTAcStore = defineStore("stac", () => {
9
+ /**
10
+ * Links of the root STAC catalog
11
+ *
12
+ * @type {import("vue").Ref<import("stac-ts").StacLink[] | null>}
13
+ */
14
+ const stac = ref(null);
15
+
16
+ /**
17
+ * Selected STAC object.
18
+ *
19
+ * @type {import("vue").Ref<
20
+ * | import("stac-ts").StacCatalog
21
+ * | import("stac-ts").StacCollection
22
+ * | import("stac-ts").StacItem
23
+ * | null
24
+ * >}
25
+ */
26
+ const selectedStac = ref(null);
27
+
28
+ const eodash = /** @type {import("@/types").Eodash} */ (inject(eodashKey));
29
+
30
+ /**
31
+ * Fetches root stac catalog and assign it to `stac`
32
+ *
33
+ * @async
34
+ * @param {import("@/types").StacEndpoint} [url=eodash.stacEndpoint] Default
35
+ * is `eodash.stacEndpoint`
36
+ * @returns {Promise<void>}
37
+ * @see {@link stac}
38
+ */
39
+ async function loadSTAC(url = eodash.stacEndpoint) {
40
+ await axios
41
+ .get(url)
42
+ .then((resp) => {
43
+ const links = /** @type {import("stac-ts").StacCatalog} */ (
44
+ resp.data
45
+ ).links.map((link) => {
46
+ if (!link.title) {
47
+ link.title = `${link.rel} ${link.href}`;
48
+ }
49
+ return link;
50
+ });
51
+ stac.value = links;
52
+ })
53
+ .catch((err) => {
54
+ throw new Error("error loading assigned STAC endpoint", err);
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Fetches selected stac object and assign it to `selectedStac`
60
+ *
61
+ * @async
62
+ * @param {string} relativePath - Stac link href
63
+ * @returns {Promise<void>}
64
+ * @see {@link selectedStac}
65
+ */
66
+ async function loadSelectedSTAC(relativePath = "") {
67
+ const absoluteUrl = useAbsoluteUrl(relativePath);
68
+
69
+ await axios
70
+ .get(absoluteUrl.value)
71
+ .then((resp) => {
72
+ selectedStac.value = resp.data;
73
+ indicator.value = selectedStac.value?.id ?? "";
74
+ })
75
+ .catch((err) => {
76
+ throw new Error("error loading the selected STAC", err);
77
+ });
78
+ }
79
+
80
+ return { stac, loadSTAC, loadSelectedSTAC, selectedStac };
81
+ });
@@ -0,0 +1,287 @@
1
+ /** @group Eodash */
2
+ export interface WebComponentProps<T extends ExecutionTime = "compiletime"> {
3
+ /**
4
+ * Imports web component file, either using a URL or an import function.
5
+ *
6
+ * @example
7
+ * importing `eox-itemfilter` web component, after installing `@eox/itemfilter` it can be
8
+ * referenced:
9
+ * ```js
10
+ * link: async() => import("@eox/itemfilter")
11
+ * ```
12
+ *
13
+ * ::: warning
14
+ * import maps are not available in runtime config
15
+ * :::
16
+ */
17
+ link: T extends "runtime" ? string : string | (() => Promise<unknown>);
18
+ /**
19
+ * Exported Constructor, needs to be provided if the web component is not
20
+ * registered in by the [link](#link) provided
21
+ */
22
+ constructorProp?: string;
23
+ tagName: `${string}-${string}`;
24
+ /** Object defining all the properties and attributes of the web component */
25
+ properties?: Record<string, unknown>;
26
+ /**
27
+ * Triggered when the web component is mounted in the DOM.
28
+ *
29
+ * @param el - Web component
30
+ * @param store - Return value of the core STAC pinia store in
31
+ * `/core/client/store/stac.ts`
32
+ */
33
+ onMounted?: (
34
+ el: Element | null,
35
+ store: ReturnType<typeof import("./store/stac").useSTAcStore>,
36
+ ) => Promise<void> | void;
37
+ /**
38
+ * Triggered when the web component is unmounted from the DOM.
39
+ *
40
+ * @param el - Web component
41
+ * @param store - Return value of the core STAC pinia store in
42
+ * `/core/client/store/stac.ts`
43
+ */
44
+ onUnmounted?: (
45
+ el: Element | null,
46
+ store: ReturnType<typeof import("./store/stac").useSTAcStore>,
47
+ ) => Promise<void> | void;
48
+ }
49
+
50
+ /** @ignore */
51
+ export interface WidgetsContainerProps {
52
+ widgets: Omit<Widget, "layout">[];
53
+ }
54
+
55
+ // eodash types:
56
+ /** Properties of EOxLayoutItem used for setting the position and size of panels */
57
+ export interface Layout {
58
+ /** Horizontal start position. Integer between 1 and 12 */
59
+ x: number;
60
+ /** Vertical start position. Integer between 1 and 12 */
61
+ y: number;
62
+ /** Width. Integer between 1 and 12 */
63
+ w: number;
64
+ /** Height. Integer between 1 and 12 */
65
+ h: number;
66
+ }
67
+ /**
68
+ * Widget type: `web-component` API
69
+ *
70
+ * @group Eodash
71
+ */
72
+ export interface WebComponentWidget<T extends ExecutionTime = "compiletime"> {
73
+ id: number | string | symbol;
74
+ title: string;
75
+ /** Widget position and size. */
76
+ layout: Layout;
77
+ widget: WebComponentProps<T>;
78
+ type: "web-component";
79
+ }
80
+
81
+ /**
82
+ * Widget type: `internal` API. Internal widgets are Vue components provided by
83
+ * eodash.
84
+ *
85
+ * @group Eodash
86
+ */
87
+ export interface InternalComponentWidget {
88
+ id: number | string | symbol;
89
+ title: string;
90
+ /** Widget position and size. */
91
+ layout: Layout;
92
+ widget: {
93
+ /**
94
+ * Internal Vue Components inside the
95
+ * [widgets](https://github.com/eodash/eodash/tree/main/widgets) folder.
96
+ * Referenced using their name without the .vue extention
97
+ */
98
+ name: string;
99
+ /** Specified Vue component props */
100
+ properties?: Record<string, unknown>;
101
+ };
102
+ type: "internal";
103
+ }
104
+
105
+ /** Widget type: `iframe` API Renders an external HTML file as a widget. */
106
+ /** @group Eodash */
107
+ export interface IFrameWidget {
108
+ id: number | string | symbol;
109
+ title: string;
110
+ /** Widget position and size. */
111
+ layout: Layout;
112
+ widget: {
113
+ /** The URL of the page to embed */
114
+ src: string;
115
+ };
116
+ type: "iframe";
117
+ }
118
+ /** @group Eodash */
119
+ export interface FunctionalWidget<T extends ExecutionTime = "compiletime"> {
120
+ /**
121
+ * Provides a functional definition of widgets, gets triggered whenever a STAC
122
+ * object is selected, and only renders the returned configuration if the `id`
123
+ * doesn't match the currently rendered `id`
124
+ *
125
+ * @param selectedSTAC - Currently selected STAC object
126
+ */
127
+ defineWidget: (
128
+ selectedSTAC:
129
+ | import("stac-ts").StacCatalog
130
+ | import("stac-ts").StacCollection
131
+ | import("stac-ts").StacItem
132
+ | null,
133
+ ) => StaticWidget<T> | undefined | null;
134
+ }
135
+ /**
136
+ * There are 3 types of Widgets:
137
+ *
138
+ * @group Eodash
139
+ */
140
+ export type StaticWidget<T extends ExecutionTime = "compiletime"> =
141
+ | WebComponentWidget<T>
142
+ | InternalComponentWidget
143
+ | IFrameWidget;
144
+ /**
145
+ * Widgets can be defined in 2 forms:
146
+ *
147
+ * 1. {@link StaticWidget} : This is defined as an object once, and is considered
148
+ * the default form.
149
+ * 2. {@link FunctionalWidget} : a special form which contains the
150
+ * {@link FunctionalWidget.defineWidget `defineWidget`} function that runs
151
+ * when {@link EodashStore.stac `loadSelectedSTAC`} function is triggered, and
152
+ * returns a value of a Static Widget or null or undefined.
153
+ *
154
+ * @group Eodash
155
+ */
156
+ export type Widget<T extends ExecutionTime = "compiletime"> =
157
+ | StaticWidget<T>
158
+ | FunctionalWidget<T>;
159
+
160
+ /** @group Eodash */
161
+ export type BackgroundWidget<T extends ExecutionTime = "compiletime"> =
162
+ | Omit<WebComponentWidget<T>, "layout" | "title" | "slidable">
163
+ | Omit<InternalComponentWidget, "layout" | "title" | "slidable">
164
+ | Omit<IFrameWidget, "layout" | "title" | "slidable">
165
+ | Omit<FunctionalWidget<T>, "layout" | "slidable">;
166
+ /**
167
+ * Dashboard rendered widgets specification. 3 types of widgets are supported:
168
+ * `"iframe"`, `"internal"`, and `"web-component"`. A specific object should be
169
+ * provided based on the type of the widget.
170
+ *
171
+ * @group Eodash
172
+ */
173
+ export interface Template<T extends ExecutionTime = "compiletime"> {
174
+ /** Gap between widgets */
175
+ gap?: number;
176
+ /** Loading widget */
177
+ loading?: BackgroundWidget<T>;
178
+ /**
179
+ * Widget rendered as the dashboard background. Has the same specifications of
180
+ * {@link Widget} without the `title` and `layout` properties
181
+ */
182
+ background?: BackgroundWidget<T>;
183
+ /** Array of widgets that will be rendered as dashboard panels. */
184
+ widgets: Widget<T>[];
185
+ }
186
+
187
+ /** @ignore */
188
+ export type StacEndpoint = `${"https://" | "http://"}${string}/catalog.json`;
189
+
190
+ /** @group Eodash */
191
+ type ExecutionTime = "runtime" | "compiletime";
192
+
193
+ /**
194
+ * Eodash instance API
195
+ *
196
+ * @group Eodash
197
+ */
198
+ export interface Eodash<T extends ExecutionTime = "compiletime"> {
199
+ /** Instance ID. */
200
+ id?: string;
201
+ /** Root STAC catalog endpoint */
202
+ stacEndpoint: StacEndpoint;
203
+ /** Brand specifications. */
204
+ brand: {
205
+ /** Removes the dashboard layout */
206
+ noLayout?: boolean;
207
+ /** Custom error message to alert the users if something crashes */
208
+ errorMessage?: string;
209
+ /** Fetches the specified font family from the specified `link` property. */
210
+ font?: {
211
+ /**
212
+ * Link to stylesheet that defines font-face. Could be either a relative
213
+ * or absolute URL.
214
+ */
215
+ link: string;
216
+ /** Font family name. */
217
+ family: string;
218
+ };
219
+ /** Title that will be shown in the app header */
220
+ name: string;
221
+ /** Brand logo */
222
+ logo?: string;
223
+ /**
224
+ * Dashboard theme as a custom [vuetifyJs
225
+ * theme](https://vuetifyjs.com/en/features/theme/).
226
+ */
227
+ theme?: import("vuetify/lib/index.mjs").ThemeDefinition;
228
+ /** Text applied to the footer. */
229
+ footerText?: string;
230
+ };
231
+ /** Template configuration */
232
+ template: Template<T>;
233
+ }
234
+ /////////
235
+
236
+ /// eodash store types
237
+ /** @group EodashStore */
238
+ export interface EodashStore {
239
+ /** Stateful Reactive variables */
240
+ states: {
241
+ /** Currently selected STAC endpoint */
242
+ currentUrl: import("vue").Ref<string>;
243
+ /** Currently selected datetime */
244
+ datetime: import("vue").Ref<string>;
245
+ /** Currently selected indicator */
246
+ indicator: import("vue").Ref<string>;
247
+
248
+ registeredProjections: `EPSG${number}`[];
249
+
250
+ /** available projection to be rendered by the Map */
251
+ availableMapProjection: import("vue").Ref<string>;
252
+ };
253
+ actions: {
254
+ /**
255
+ * returns the layers of the `eox-map`
256
+ * @param [el] - `eox-map` element selector
257
+ */
258
+ getLayers: (el?: string) => object[];
259
+
260
+ /**
261
+ * Register EPSG projection in `eox-map` and adds it to {@link EodashStore.states.availableMapProjection `availableMapProjection`` }
262
+ * */
263
+ registerProjection: (code?: number | string) => Promise<void>;
264
+
265
+ /** Change `eox-map` projection from an `EPSG` code */
266
+ changeMapProjection: (code?: number | string) => Promise<void>;
267
+ };
268
+
269
+ /** Pinia store definition used to navigate the root STAC catalog. */
270
+ stac: {
271
+ useSTAcStore: typeof import("./store/stac.js").useSTAcStore;
272
+ };
273
+ }
274
+ ///////
275
+ /**
276
+ * The project's entry point should export this function as a default to
277
+ * instantiate eodash
278
+ *
279
+ * @param config
280
+ * @group Eodash
281
+ */
282
+ export declare const createEodash: (
283
+ config: ((store: EodashStore) => Eodash | Promise<Eodash>) | Eodash,
284
+ ) => Eodash | Promise<Eodash>;
285
+
286
+ /** @group EodashStore */
287
+ export declare const store: EodashStore;
@@ -0,0 +1,337 @@
1
+ import { Collection, Item } from "stac-js";
2
+ import { toAbsolute } from "stac-js/src/http.js";
3
+ import {
4
+ createLayersFromDataAssets,
5
+ extractLayerConfig,
6
+ generateFeatures,
7
+ setMapProjFromCol,
8
+ } from "./helpers";
9
+ import axios from "axios";
10
+ import { registerProjection } from "@/store/Actions";
11
+
12
+ export class EodashCollection {
13
+ /** @type {string} */
14
+ #collectionUrl = "";
15
+ /** @type {import("stac-ts").StacCollection | undefined} */
16
+ #collectionStac;
17
+ /**
18
+ * @type {import("stac-ts").StacLink
19
+ * | import("stac-ts").StacItem
20
+ * | undefined}
21
+ */
22
+ selectedItem;
23
+
24
+ /** @param {string} collectionUrl */
25
+ constructor(collectionUrl) {
26
+ this.#collectionUrl = collectionUrl;
27
+ }
28
+ /**
29
+ * @async
30
+ * @param {import('stac-ts').StacLink | Date} [itemLinkOrDate]
31
+ * @returns
32
+ */
33
+ createLayersJson = async (itemLinkOrDate) => {
34
+ /** @type {import("stac-ts").StacLink | undefined} */
35
+ let stacItem,
36
+ /** @type {import("stac-ts").StacCollection | undefined} */
37
+ stac;
38
+ // TODO get auxiliary layers from collection
39
+ /** @type {object[]} */
40
+ let layersJson = [];
41
+
42
+ // Load collectionstac if not yet initialized
43
+ if (!this.#collectionStac) {
44
+ const response = await axios.get(this.#collectionUrl);
45
+ stac = await response.data;
46
+ this.#collectionStac = new Collection(stac);
47
+ }
48
+
49
+ // set availabe map projection
50
+ setMapProjFromCol(this.#collectionStac);
51
+
52
+ if (stac && stac.endpointtype === "GeoDB") {
53
+ // Special handling of point based data
54
+ const allFeatures = generateFeatures(stac.links);
55
+ layersJson.unshift({
56
+ type: "Vector",
57
+ properties: {
58
+ id: stac.id,
59
+ title: stac.title || stac.id,
60
+ },
61
+ source: {
62
+ type: "Vector",
63
+ url: "data:," + encodeURIComponent(JSON.stringify(allFeatures)),
64
+ format: "GeoJSON",
65
+ },
66
+ style: {
67
+ "circle-radius": 5,
68
+ "circle-fill-color": "#00417077",
69
+ "circle-stroke-color": "#004170",
70
+ "fill-color": "#00417077",
71
+ "stroke-color": "#004170",
72
+ },
73
+ });
74
+
75
+ return layersJson;
76
+ } else {
77
+ if (itemLinkOrDate instanceof Date) {
78
+ // if collectionStac not yet initialized we do it here
79
+ stacItem = this.getItems()?.sort((a, b) => {
80
+ const distanceA = Math.abs(
81
+ new Date(/** @type {number} */ (a.datetime)).getTime() -
82
+ itemLinkOrDate.getTime(),
83
+ );
84
+ const distanceB = Math.abs(
85
+ new Date(/** @type {number} */ (b.datetime)).getTime() -
86
+ itemLinkOrDate.getTime(),
87
+ );
88
+ return distanceA - distanceB;
89
+ })[0];
90
+ this.selectedItem = stacItem;
91
+ } else {
92
+ stacItem = itemLinkOrDate;
93
+ }
94
+
95
+ const stacItemUrl = stacItem
96
+ ? toAbsolute(stacItem.href, this.#collectionUrl)
97
+ : this.#collectionUrl;
98
+ stac = await axios.get(stacItemUrl).then((resp) => resp.data);
99
+
100
+ if (!stacItem) {
101
+ // no specific item was requested; render last item
102
+ this.#collectionStac = new Collection(stac);
103
+ const items = this.getItems();
104
+ this.selectedItem = items?.[items.length - 1];
105
+ if (this.selectedItem) {
106
+ layersJson = await this.createLayersJson(this.selectedItem);
107
+ } else {
108
+ if (import.meta.env.DEV) {
109
+ console.warn(
110
+ "[eodash] the selected collection does not include any items",
111
+ );
112
+ }
113
+ }
114
+ return [];
115
+ } else {
116
+ // specific item was requested
117
+ const item = new Item(stac);
118
+ this.selectedItem = item;
119
+ const title = this.#collectionStac.title || this.#collectionStac.id;
120
+ layersJson.unshift(
121
+ ...(await this.buildJsonArray(item, stacItemUrl, title)),
122
+ );
123
+ return layersJson;
124
+ }
125
+ }
126
+ };
127
+
128
+ async getExtent() {
129
+ if (!this.#collectionStac) {
130
+ const response = await axios.get(this.#collectionUrl);
131
+ const stac = await response.data;
132
+ this.#collectionStac = new Collection(stac);
133
+ }
134
+ return this.#collectionStac?.extent;
135
+ }
136
+ /**
137
+ * @param {object} properties
138
+ * @param {[string]} roles
139
+ * */
140
+ extractRoles(properties, roles) {
141
+ roles?.forEach((role) => {
142
+ if (role === "visible") {
143
+ // @ts-expect-error visible does not need to exist in properties
144
+ properties.visible = true;
145
+ }
146
+ if (role === "overlay" || role === "baselayer") {
147
+ // @ts-expect-error group not expected to exist in properties
148
+ properties.group = role;
149
+ }
150
+ });
151
+ }
152
+ /**
153
+ * @param {import("stac-ts").StacItem} item
154
+ * @param {string} itemUrl
155
+ * @param {string} title
156
+ * */
157
+ async buildJsonArray(item, itemUrl, title) {
158
+ const jsonArray = [];
159
+ // TODO: this currently assumes only one layer will be extracted
160
+ // from an item, although it think this is currently true
161
+ // potentially this could return multiple layers
162
+ // TODO: implement other types, such as COG
163
+
164
+ // I propose following approach, we "manually" create configurations
165
+ // for the rendering options we know and expect.
166
+ // If we don't find any we fallback to using the STAC ol item that
167
+ // will try to extract anything it supports but for which we have
168
+ // less control.
169
+ let dataAssets = /** @type {Record<string,import('stac-ts').StacAsset>} */ ({});
170
+ if (item.assets) {
171
+ dataAssets = Object.keys(item.assets).reduce((data, ast) => {
172
+ if (item.assets[ast].roles?.includes("data")) {
173
+ data[ast] = item.assets[ast];
174
+ }
175
+ return data;
176
+ }, /** @type {Record<string,import('stac-ts').StacAsset>} */ ({}));
177
+ }
178
+
179
+ const { layerConfig, style } = extractLayerConfig(
180
+ await this.fetchStyle(item, itemUrl),
181
+ );
182
+ const wmsArray = item.links.filter((l) => l.rel === "wms");
183
+ const xyzArray = item.links.filter((l) => l.rel === "xyz");
184
+ const fallbackToStac = item.links.find((l) => l.rel === "wmts");
185
+
186
+ // TODO: add capability to find projection in item
187
+ await registerProjection(
188
+ /** @type {number | undefined} */ (item?.["proj:epsg"]),
189
+ );
190
+
191
+ if (wmsArray.length > 0) {
192
+ wmsArray.forEach((link) => {
193
+ let json = {
194
+ type: "Tile",
195
+ properties: {
196
+ id: link.id || item.id,
197
+ title: title || link.title || item.id,
198
+ },
199
+ source: {
200
+ // TODO: if no projection information is provided we should
201
+ // assume one, else for WMS requests it will try to get
202
+ // the map projection that might not be supported
203
+ // projection: projDef ? projDef : "EPSG:4326",
204
+ type: "TileWMS",
205
+ url: link.href,
206
+ params: {
207
+ LAYERS: link["wms:layers"],
208
+ TILED: true,
209
+ },
210
+ },
211
+ };
212
+ this.extractRoles(
213
+ json.properties,
214
+ /** @type {[string]} */ (link.roles),
215
+ );
216
+ if ("wms:dimensions" in link) {
217
+ // Expand all dimensions into the params attribute
218
+ json.source.params = Object.assign(
219
+ json.source.params,
220
+ link["wms:dimensions"],
221
+ );
222
+ }
223
+ jsonArray.push(json);
224
+ });
225
+ } else if (xyzArray.length > 0) {
226
+ xyzArray.forEach((link) => {
227
+ let json = {
228
+ type: "Tile",
229
+ properties: {
230
+ id: link.id || item.id,
231
+ title: title || link.title || item.id,
232
+ roles: link.roles,
233
+ },
234
+ source: {
235
+ type: "XYZ",
236
+ url: link.href,
237
+ },
238
+ };
239
+ this.extractRoles(
240
+ json.properties,
241
+ /** @type {[string]} */ (link.roles),
242
+ );
243
+ jsonArray.push(json);
244
+ });
245
+ } else if (fallbackToStac) {
246
+ jsonArray.push({
247
+ type: "STAC",
248
+ displayWebMapLink: true,
249
+ displayFootprint: false,
250
+ data: item,
251
+ properties: {
252
+ id: item.id,
253
+ title: title || item.id,
254
+ },
255
+ });
256
+ } else if (Object.keys(dataAssets).length) {
257
+ jsonArray.push(
258
+ ...(await createLayersFromDataAssets(
259
+ this.#collectionStac?.title || item.id,
260
+ this.#collectionStac?.title || item.id,
261
+ dataAssets,
262
+ style,
263
+ layerConfig,
264
+ )),
265
+ );
266
+ } else if (item.geometry) {
267
+ // fall back to rendering the feature
268
+ jsonArray.push({
269
+ type: "Vector",
270
+ source: {
271
+ type: "Vector",
272
+ url: "data:," + encodeURIComponent(JSON.stringify(item.geometry)),
273
+ format: "GeoJSON",
274
+ },
275
+ properties: {
276
+ id: item.id,
277
+ title: this.#collectionStac?.title || item.id,
278
+ layerConfig: {
279
+ ...layerConfig,
280
+ style,
281
+ },
282
+ },
283
+ });
284
+ }
285
+
286
+ return jsonArray;
287
+ }
288
+
289
+ getItems() {
290
+ return (
291
+ this.#collectionStac?.links
292
+ .filter((i) => i.rel === "item")
293
+ // sort by `datetime`, where oldest is first in array
294
+ .sort((a, b) =>
295
+ /** @type {number} */ (a.datetime) <
296
+ /** @type {number} */ (b.datetime)
297
+ ? -1
298
+ : 1,
299
+ )
300
+ );
301
+ }
302
+
303
+ /**
304
+ * @param {import("stac-ts").StacItem} item
305
+ * @param {string} itemUrl
306
+ **/
307
+ async fetchStyle(item, itemUrl) {
308
+ const styleLink = item.links.find((link) => link.rel.includes("style"));
309
+ if (styleLink) {
310
+ let url = "";
311
+ if (styleLink.href.startsWith("http")) {
312
+ url = styleLink.href;
313
+ } else {
314
+ url = toAbsolute(styleLink.href, itemUrl);
315
+ }
316
+
317
+ /** @type {import("ol/layer/WebGLTile").Style & {jsonform?:object}} */
318
+ const styleJson = await axios.get(url).then((resp) => resp.data);
319
+ return styleJson;
320
+ }
321
+ }
322
+
323
+ getDates() {
324
+ return (
325
+ this.#collectionStac?.links
326
+ .filter((i) => i.rel === "item")
327
+ // sort by `datetime`, where oldest is first in array
328
+ .sort((a, b) =>
329
+ /** @type {number} */ (a.datetime) <
330
+ /** @type {number} */ (b.datetime)
331
+ ? -1
332
+ : 1,
333
+ )
334
+ .map((i) => new Date(/** @type {number} */ (i.datetime)))
335
+ );
336
+ }
337
+ }