@eodash/eodash 5.0.0-rc.1.5 → 5.0.0-rc.2

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 (62) hide show
  1. package/README.md +1 -1
  2. package/core/client/composables/EodashMap.js +47 -28
  3. package/core/client/composables/EodashProcess.js +51 -5
  4. package/core/client/composables/index.js +8 -1
  5. package/core/client/eodash.js +21 -7
  6. package/core/client/eodashSTAC/EodashCollection.js +24 -4
  7. package/core/client/eodashSTAC/createLayers.js +62 -6
  8. package/core/client/eodashSTAC/helpers.js +48 -5
  9. package/core/client/eodashSTAC/triggers.js +52 -1
  10. package/core/client/store/stac.js +7 -2
  11. package/core/client/types.ts +10 -1
  12. package/core/client/utils/index.js +12 -0
  13. package/core/client/utils/states.js +18 -1
  14. package/core/client/views/Dashboard.vue +3 -1
  15. package/dist/client/{DashboardLayout-B-4X57-t.js → DashboardLayout-VrJIbhe8.js} +2 -2
  16. package/dist/client/{DynamicWebComponent-Dj3QYwag.js → DynamicWebComponent-BCwpocDX.js} +1 -1
  17. package/dist/client/EodashDatePicker-Bp5ec3BC.js +430 -0
  18. package/dist/client/{EodashItemFilter-DBQwJQPh.js → EodashItemFilter-Cx0t-qeW.js} +1 -1
  19. package/dist/client/{EodashLayerControl-C5fOCvoI.js → EodashLayerControl-DERx00In.js} +10 -2
  20. package/dist/client/{EodashLayoutSwitcher-BMO9k_20.js → EodashLayoutSwitcher-DTS7otlk.js} +2 -2
  21. package/dist/client/{EodashMap-D2bnMLAC.js → EodashMap-C-I6puhb.js} +101 -73
  22. package/dist/client/{EodashMapBtns-l9B977id.js → EodashMapBtns-CWgtJiG4.js} +4 -4
  23. package/dist/client/{EodashProcess-BtIlJvF1.js → EodashProcess-DWrTIyHT.js} +188 -33
  24. package/dist/client/{EodashStacInfo-CPVvp_Hm.js → EodashStacInfo-Dvsk97Mz.js} +1 -1
  25. package/dist/client/{EodashTools-DY2dlNXW.js → EodashTools-CdnjgTTl.js} +4 -4
  26. package/dist/client/{ExportState-BvD5A0XG.js → ExportState-S4lcehm3.js} +4 -4
  27. package/dist/client/{Footer-w95gBnSH.js → Footer-DlIEbXp-.js} +1 -1
  28. package/dist/client/{Header-BpiorKy9.js → Header-CTiEXLi0.js} +3 -3
  29. package/dist/client/{MobileLayout-CmVlZe7S.js → MobileLayout-DRgyQYFz.js} +17 -7
  30. package/dist/client/{PopUp-CREaSybs.js → PopUp-CzqV8BFZ.js} +3 -3
  31. package/dist/client/{VImg-DF9esgdd.js → VImg-Bn8bCvVM.js} +2 -2
  32. package/dist/client/{VMain-BWLMf-rn.js → VMain-2GOqWb6m.js} +1 -1
  33. package/dist/client/{VOverlay-DmNfblmy.js → VOverlay-BetC0LGI.js} +3 -3
  34. package/dist/client/{VTooltip-C3PeE7iO.js → VTooltip-BWg0dxx5.js} +3 -3
  35. package/dist/client/{WidgetsContainer-6FHEEXns.js → WidgetsContainer-Cv466WUW.js} +1 -1
  36. package/dist/client/{asWebComponent-BnFMd0T6.js → asWebComponent-CLUhauLl.js} +422 -164
  37. package/dist/client/eo-dash.css +1 -1
  38. package/dist/client/eo-dash.js +1 -1
  39. package/dist/client/{forwardRefs-BF3Me2RX.js → forwardRefs-CxSsJulB.js} +1 -1
  40. package/dist/client/{index-CRd5-RSy.js → index-BMj56LY3.js} +1 -1
  41. package/dist/client/{transition-Cpn_g5jE.js → transition-DidoPMgC.js} +1 -1
  42. package/dist/node/cli.js +2 -2
  43. package/dist/types/core/client/composables/EodashMap.d.ts +2 -1
  44. package/dist/types/core/client/composables/EodashProcess.d.ts +17 -11
  45. package/dist/types/core/client/composables/index.d.ts +1 -1
  46. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +11 -4
  47. package/dist/types/core/client/eodashSTAC/createLayers.d.ts +6 -6
  48. package/dist/types/core/client/eodashSTAC/helpers.d.ts +77 -20
  49. package/dist/types/core/client/eodashSTAC/triggers.d.ts +6 -0
  50. package/dist/types/core/client/types.d.ts +13 -1
  51. package/dist/types/core/client/utils/index.d.ts +1 -0
  52. package/dist/types/core/client/utils/states.d.ts +9 -0
  53. package/dist/types/widgets/EodashDatePicker.vue.d.ts +459 -2
  54. package/dist/types/widgets/EodashMap.vue.d.ts +2 -0
  55. package/dist/types/widgets/EodashProcess.vue.d.ts +1 -0
  56. package/dist/types/widgets/PopUp.vue.d.ts +1 -2
  57. package/package.json +24 -24
  58. package/widgets/EodashDatePicker.vue +139 -22
  59. package/widgets/EodashLayerControl.vue +13 -1
  60. package/widgets/EodashMap.vue +63 -5
  61. package/widgets/EodashProcess.vue +82 -22
  62. package/dist/client/EodashDatePicker-DGRJrJ0s.js +0 -306
package/README.md CHANGED
@@ -44,7 +44,7 @@ npm run build -- --lib
44
44
  ├── core # CLI & Client source code
45
45
  ├── docs # Documentation files
46
46
  ├── tests # CLI & Client component tests folder
47
- ├── widgets # Vue componenets as internal widgets.
47
+ ├── widgets # Vue components as internal widgets.
48
48
  ├── public # Statically served directory
49
49
  └── README.md
50
50
 
@@ -7,9 +7,10 @@ import { storeToRefs } from "pinia";
7
7
  import { useEventBus } from "@vueuse/core";
8
8
  import { eoxLayersKey } from "@/utils/keys";
9
9
  import { posIsSetFromUrl } from "@/utils/states";
10
+ import { useOnLayersUpdate } from ".";
10
11
  /**
11
12
  * Holder for previous compare map view as it is overwritten by sync
12
- * @type { {map:import("ol").View } | null} mapElement
13
+ * @type { import("ol").View | null} mapElement
13
14
  */
14
15
  let viewHolder = null;
15
16
 
@@ -203,12 +204,13 @@ const createLayersConfig = async (
203
204
  /**
204
205
  * Initializes the map and updates it based on changes in the selected indicator and datetime,
205
206
  *
206
- * @param {import("vue").Ref<HTMLElement & Record<string,any> | null>} mapElement
207
+ * @param {import("vue").Ref<import("@eox/map").EOxMap| null>} mapElement
207
208
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} selectedIndicator
208
209
  * @param {EodashCollection[]} eodashCols
209
210
  * @param {import("vue").Ref<string>} datetime
210
211
  * @param {import("vue").Ref<Record<string,any>[]>} mapLayers
211
- * @param {import("vue").Ref<HTMLElement & Record<string,any> | null>} partnerMap
212
+ * @param {import("vue").Ref<import("@eox/map").EOxMap| null>} partnerMap
213
+ * @param {boolean} zoomToExtent
212
214
  */
213
215
  export const useInitMap = (
214
216
  mapElement,
@@ -217,6 +219,7 @@ export const useInitMap = (
217
219
  datetime,
218
220
  mapLayers,
219
221
  partnerMap,
222
+ zoomToExtent,
220
223
  ) => {
221
224
  log.debug(
222
225
  "InitMap",
@@ -260,7 +263,7 @@ export const useInitMap = (
260
263
  // Compare map being initialized
261
264
  if (selectedCompareStac.value !== null) {
262
265
  // save view of compare map
263
- viewHolder = mapElement?.value?.map.getView();
266
+ viewHolder = mapElement?.value?.map.getView() ?? null;
264
267
  /** @type {any} */
265
268
  (mapElement.value).sync = partnerMap.value;
266
269
  }
@@ -309,29 +312,31 @@ export const useInitMap = (
309
312
  datetime.value = endInterval.toISOString();
310
313
  }
311
314
 
312
- // Try to move map view to extent only when main
313
- // indicator and map changes
314
- if (
315
- mapElement?.value?.id === "main" &&
316
- updatedStac.extent?.spatial.bbox &&
317
- !posIsSetFromUrl.value
318
- ) {
319
- // Sanitize extent,
320
- const b = updatedStac.extent?.spatial.bbox[0];
321
- const sanitizedExtent = [
322
- b?.[0] > -180 ? b?.[0] : -180,
323
- b?.[1] > -90 ? b?.[1] : -90,
324
- b?.[2] < 180 ? b?.[2] : 180,
325
- b?.[3] < 90 ? b?.[3] : 90,
326
- ];
327
-
328
- const reprojExtent = mapElement.value?.transformExtent(
329
- sanitizedExtent,
330
- "EPSG:4326",
331
- mapElement.value?.map?.getView().getProjection(),
332
- );
333
- /** @type {import("@eox/map").EOxMap} */
334
- (mapElement.value).zoomExtent = reprojExtent;
315
+ if (zoomToExtent) {
316
+ // Try to move map view to extent only when main
317
+ // indicator and map changes
318
+ if (
319
+ mapElement?.value?.id === "main" &&
320
+ updatedStac.extent?.spatial.bbox &&
321
+ !posIsSetFromUrl.value
322
+ ) {
323
+ // Sanitize extent,
324
+ const b = updatedStac.extent?.spatial.bbox[0];
325
+ const sanitizedExtent = [
326
+ b?.[0] > -180 ? b?.[0] : -180,
327
+ b?.[1] > -90 ? b?.[1] : -90,
328
+ b?.[2] < 180 ? b?.[2] : 180,
329
+ b?.[3] < 90 ? b?.[3] : 90,
330
+ ];
331
+
332
+ const reprojExtent = mapElement.value?.transformExtent(
333
+ sanitizedExtent,
334
+ "EPSG:4326",
335
+ mapElement.value?.map?.getView().getProjection(),
336
+ );
337
+ /** @type {import("@eox/map").EOxMap} */
338
+ (mapElement.value).zoomExtent = reprojExtent;
339
+ }
335
340
  }
336
341
  if (posIsSetFromUrl.value) {
337
342
  posIsSetFromUrl.value = false;
@@ -341,7 +346,6 @@ export const useInitMap = (
341
346
  "Assigned layers",
342
347
  JSON.parse(JSON.stringify(layersCollection)),
343
348
  );
344
-
345
349
  mapLayers.value = layersCollection;
346
350
  // Emit event to update layers
347
351
  await nextTick(() => {
@@ -358,3 +362,18 @@ export const useInitMap = (
358
362
  stopIndicatorWatcher();
359
363
  });
360
364
  };
365
+ /**
366
+ *
367
+ * @param {EodashCollection[]} eodashCols
368
+ * @param {import("vue").Ref<Exclude<import("@/types").EodashStyleJson["tooltip"],undefined>>} tooltipProperties
369
+ */
370
+ export const useUpdateTooltipProperties = (eodashCols, tooltipProperties) => {
371
+ useOnLayersUpdate(async () => {
372
+ const tooltips = [];
373
+ for (const ec of eodashCols) {
374
+ tooltips.push(...(await ec.getToolTipProperties()));
375
+ }
376
+ tooltipProperties.value = tooltips;
377
+ log.debug("Updated tooltip properties", tooltipProperties.value);
378
+ });
379
+ };
@@ -48,6 +48,10 @@ export async function pollProcessStatus({
48
48
  console.log("Result file fetched successfully:", resultResponse.data);
49
49
  return resultResponse.data; // Return the json result list
50
50
  }
51
+ if (processReport.status === "failed") {
52
+ isPolling.value = false;
53
+ throw new Error("Process failed.", processReport);
54
+ }
51
55
 
52
56
  // Log the current status if not successful
53
57
  console.log(
@@ -370,7 +374,7 @@ export async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
370
374
  * @param {import("stac-ts").StacLink[] | undefined} links
371
375
  * @param {Record<string,any> | undefined} jsonformValue
372
376
  * @param {string} specUrl
373
- * @returns {Promise<[import("vega").Spec|null,Record<string,any>|null]>}
377
+ * @returns {Promise<[import("@eox/chart").EOxChart["spec"] | null,Record<string,any>|null]>}
374
378
  **/
375
379
  export async function getChartValues(links, jsonformValue, specUrl) {
376
380
  if (!specUrl || !links) return [null, null];
@@ -419,9 +423,10 @@ export async function getChartValues(links, jsonformValue, specUrl) {
419
423
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
420
424
  * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
421
425
  * @param {import("vue").Ref<Record<string,any>|null>} params.jsonformSchema
422
- * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
426
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
423
427
  * @param {import("vue").Ref<Record<string, any> | null>} params.chartData
424
428
  * @param {import("vue").Ref<boolean>} params.isPolling
429
+ * @param {import("vue").Ref<any[]>} params.processResults
425
430
  */
426
431
  export async function handleProcesses({
427
432
  loading,
@@ -431,6 +436,7 @@ export async function handleProcesses({
431
436
  chartSpec,
432
437
  chartData,
433
438
  isPolling,
439
+ processResults,
434
440
  }) {
435
441
  log.debug("Processing...");
436
442
  loading.value = true;
@@ -456,22 +462,50 @@ export async function handleProcesses({
456
462
  { ...(jsonformValue ?? {}) },
457
463
  specUrl,
458
464
  );
465
+ if (Object.keys(chartData.value ?? {}).length) {
466
+ processResults.value.push(chartData.value);
467
+ }
468
+ //@ts-expect-error we assume that the spec data is of type InlineData
469
+ if (chartSpec.value?.data?.values?.length) {
470
+ //@ts-expect-error we assume that the spec data is of type InlineData
471
+ processResults.value.push(chartSpec.value?.data.values);
472
+ }
473
+
459
474
  if (chartSpec.value && !("background" in chartSpec.value)) {
460
475
  chartSpec.value["background"] = "transparent";
461
476
  }
477
+
462
478
  const geotiffLayer = await processGeoTiff(
463
479
  serviceLinks,
464
480
  jsonformValue,
465
481
  selectedStac.value?.id ?? "",
466
482
  isPolling,
467
483
  );
484
+
485
+ if (geotiffLayer && geotiffLayer.source?.sources.length) {
486
+ processResults.value.push(
487
+ ...(geotiffLayer.source?.sources?.map((source) => source.url) ?? []),
488
+ );
489
+ }
490
+ // 3. vector geojson
468
491
  const vectorLayers = await processVector(
469
492
  serviceLinks,
470
493
  jsonformValue,
471
494
  selectedStac.value?.id ?? "",
472
495
  );
473
496
 
497
+ if (vectorLayers?.length) {
498
+ processResults.value.push(
499
+ ...vectorLayers.map((layer) => layer.source?.url),
500
+ );
501
+ }
502
+
474
503
  const imageLayers = processImage(serviceLinks, jsonformValue, origBbox);
504
+ if (imageLayers?.length) {
505
+ processResults.value.push(
506
+ ...imageLayers.map((layer) => layer.source?.url),
507
+ );
508
+ }
475
509
 
476
510
  log.debug(
477
511
  "rendered layers after processing:",
@@ -509,8 +543,9 @@ export async function handleProcesses({
509
543
  * @param {Object} params
510
544
  * @param {import("vue").Ref<boolean>} params.loading
511
545
  * @param {import("vue").Ref<boolean>} params.isProcessed
512
- * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
546
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
513
547
  * @param {import("vue").Ref<boolean>} params.isPolling
548
+ * @param {import("vue").Ref<any[]>} params.processResults
514
549
  * @param {import("vue").Ref<Record<string,any>|null>} params.jsonformSchema
515
550
  */
516
551
  export function resetProcess({
@@ -518,12 +553,14 @@ export function resetProcess({
518
553
  isProcessed,
519
554
  chartSpec,
520
555
  jsonformSchema,
556
+ processResults,
521
557
  isPolling,
522
558
  }) {
523
559
  loading.value = false;
524
560
  isProcessed.value = false;
525
561
  isPolling.value = false;
526
562
  chartSpec.value = null;
563
+ processResults.value = [];
527
564
  jsonformSchema.value = null;
528
565
  }
529
566
 
@@ -536,7 +573,8 @@ export function resetProcess({
536
573
  * @param {import("vue").Ref<import("stac-ts").StacCollection>} params.selectedStac
537
574
  * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
538
575
  * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
539
- * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
576
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
577
+ * @param {import("vue").Ref<any[]>} params.processResults
540
578
  * @param {import("vue").Ref<boolean>} params.isProcessed
541
579
  * @param {import("vue").Ref<boolean>} params.loading
542
580
  * @param {import("vue").Ref<boolean>} params.isPolling
@@ -547,13 +585,21 @@ export async function initProcess({
547
585
  jsonformSchema,
548
586
  chartSpec,
549
587
  isProcessed,
588
+ processResults,
550
589
  loading,
551
590
  isPolling,
552
591
  }) {
553
592
  if (!selectedStac.value) {
554
593
  return;
555
594
  }
556
- resetProcess({ loading, isProcessed, chartSpec, jsonformSchema, isPolling });
595
+ resetProcess({
596
+ loading,
597
+ isProcessed,
598
+ chartSpec,
599
+ jsonformSchema,
600
+ isPolling,
601
+ processResults,
602
+ });
557
603
  if (selectedStac.value["eodash:jsonform"]) {
558
604
  jsonformEl.value?.editor.destroy();
559
605
  // wait for the layers to be rendered
@@ -17,6 +17,7 @@ import log from "loglevel";
17
17
  import { eodashKey, eoxLayersKey } from "@/utils/keys";
18
18
  import { useEventBus } from "@vueuse/core";
19
19
  import { posIsSetFromUrl } from "@/utils/states";
20
+ import { setCollectionsPalette } from "@/utils";
20
21
 
21
22
  /**
22
23
  * Creates an absolute URL from a relative link and assignes it to `currentUrl`
@@ -81,13 +82,19 @@ export const useCompareAbsoluteUrl = (rel = "", base = eodash.stacEndpoint) => {
81
82
  * `ThemeDefinition`
82
83
  *
83
84
  * @param {string} themeName - Name of the theme to be updated
84
- * @param {import("vuetify").ThemeDefinition} [themeDefinition={}] - New
85
+ * @param {import("@/types").Eodash["brand"]["theme"]} [themeDefinition={}] - New
85
86
  * defintion to be updated to. Default is `{}`
86
87
  * @returns {import("vuetify").ThemeInstance}
87
88
  */
88
89
  export const useUpdateTheme = (themeName, themeDefinition = {}) => {
89
90
  const theme = useTheme();
90
91
 
92
+ // extract collections palette from the theme
93
+ if (themeDefinition.collectionsPalette?.length) {
94
+ setCollectionsPalette(themeDefinition.collectionsPalette);
95
+ delete themeDefinition.collectionsPalette;
96
+ }
97
+
91
98
  /** @type {(keyof import("vuetify").ThemeDefinition)[]} */ (
92
99
  Object.keys(themeDefinition)
93
100
  ).forEach((key) => {
@@ -12,9 +12,11 @@ export const eodash = reactive({
12
12
  stacEndpoint:
13
13
  // "https://eurodatacube.github.io/eodash-catalog/RACE/catalog.json",
14
14
  // "https://gtif-cerulean.github.io/catalog/cerulean/catalog.json",
15
- "https://eodashcatalog.eox.at/samplecatalog/samples/catalog.json",
16
- // "https://eodashcatalog.eox.at/test-style/trilateral/catalog.json",
17
- // "https://gtif-cerulean.github.io/catalog/cerulean/catalog.json",
15
+ // "https://eodashcatalog.eox.at/samplecatalog/samples/catalog.json",
16
+ // "https://eodashcatalog.eox.at/test-style/trilateral/catalog.json",
17
+ // "https://gtif-cerulean.github.io/catalog/cerulean/catalog.json",
18
+ // "https://gtif-cerulean.github.io/deside-catalog/deside/catalog.json",
19
+ "https://gtif-cerulean.github.io/cerulean-catalog/cerulean/catalog.json",
18
20
  brand: {
19
21
  noLayout: true,
20
22
  name: "Demo",
@@ -28,6 +30,18 @@ export const eodash = reactive({
28
30
  "surface-opacity": 0.6,
29
31
  "primary-opacity": 0.8,
30
32
  },
33
+ // Bank-Wong palette
34
+ collectionsPalette: [
35
+ "#009E73",
36
+ "#E69F00",
37
+ "#56B4E9",
38
+ "#009E73",
39
+ "#F0E442",
40
+ "#0072B2",
41
+ "#D55E00",
42
+ "#CC79A7",
43
+ "#994F00",
44
+ ],
31
45
  },
32
46
  footerText: "Demo configuration of eodash client",
33
47
  },
@@ -145,8 +159,6 @@ export const eodash = reactive({
145
159
  widget: {
146
160
  name: "EodashDatePicker",
147
161
  properties: {
148
- hideArrows: true,
149
- hideInputField: true,
150
162
  hintText: `<b>Hint:</b> closest available date is displayed <br />
151
163
  on map (see Analysis Layers)`,
152
164
  },
@@ -247,6 +259,7 @@ export const eodash = reactive({
247
259
  properties: {
248
260
  hintText: `<b>Hint:</b> closest available date is displayed <br />
249
261
  on map (see Analysis Layers)`,
262
+ toggleCalendar: true,
250
263
  },
251
264
  },
252
265
  }
@@ -272,10 +285,10 @@ export const eodash = reactive({
272
285
  defineWidget: (selectedSTAC) =>
273
286
  selectedSTAC?.links.some((l) => l.rel === "service")
274
287
  ? {
275
- id: Symbol(),
288
+ id: "Processes",
276
289
  type: "internal",
277
290
  title: "Processes",
278
- layout: { x: 0, y: 7, w: 3, h: 5 },
291
+ layout: { x: 9, y: 7, w: 3, h: 5 },
279
292
  widget: {
280
293
  name: "EodashProcess",
281
294
  },
@@ -419,6 +432,7 @@ export const eodash = reactive({
419
432
  properties: {
420
433
  hintText: `<b>Hint:</b> closest available date is displayed <br />
421
434
  on map (see Analysis Layers)`,
435
+ toggleCalendar: true,
422
436
  },
423
437
  },
424
438
  }
@@ -31,6 +31,12 @@ export class EodashCollection {
31
31
  */
32
32
  selectedItem;
33
33
 
34
+ /** @type {Exclude<import("@/types").EodashStyleJson["tooltip"],undefined>} */
35
+ #tooltipProperties = [];
36
+
37
+ /** @type {string | undefined} */
38
+ color;
39
+
34
40
  // read only
35
41
  get collectionStac() {
36
42
  return this.#collectionStac;
@@ -145,6 +151,7 @@ export class EodashCollection {
145
151
  // less control.
146
152
 
147
153
  let { layerConfig, style } = extractLayerConfig(
154
+ this.#collectionStac?.id ?? "",
148
155
  await fetchStyle(item, itemUrl),
149
156
  );
150
157
 
@@ -179,6 +186,10 @@ export class EodashCollection {
179
186
  layerLegend: this.#collectionStac["eox:colorlegend"],
180
187
  };
181
188
  }
189
+ extraProperties = {
190
+ ...extraProperties,
191
+ ...(this.color && { color: this.color }),
192
+ };
182
193
  const links = await createLayersFromLinks(
183
194
  this.#collectionStac?.id ?? "",
184
195
  title,
@@ -290,6 +301,19 @@ export class EodashCollection {
290
301
  : this.getItems()?.at(-1);
291
302
  }
292
303
 
304
+ async getToolTipProperties() {
305
+ if (!(this.selectedItem instanceof Item)) {
306
+ return [];
307
+ }
308
+ let styles = await fetchStyle(
309
+ this.selectedItem,
310
+ `${this.#collectionUrl}/${this.selectedItem.id}`,
311
+ );
312
+ const { tooltip } = styles || { tooltip: [] };
313
+ this.#tooltipProperties = tooltip ?? [];
314
+ return this.#tooltipProperties;
315
+ }
316
+
293
317
  /**
294
318
  *
295
319
  * @param {string} datetime
@@ -358,7 +382,6 @@ export class EodashCollection {
358
382
  indicator?.title || indicator.id,
359
383
  //@ts-expect-error indicator instead of item
360
384
  indicator,
361
- // layerDatetime,
362
385
  )),
363
386
  ...(await createLayersFromAssets(
364
387
  indicator?.id ?? "",
@@ -366,9 +389,6 @@ export class EodashCollection {
366
389
  indicatorAssets,
367
390
  //@ts-expect-error indicator instead of item
368
391
  indicator,
369
- // style,
370
- // layerConfig,
371
- // layerDatetime,
372
392
  )),
373
393
  ];
374
394
  }
@@ -5,6 +5,7 @@ import {
5
5
  getProjectionCode,
6
6
  createLayerID,
7
7
  createAssetID,
8
+ mergeGeojsons,
8
9
  } from "./helpers";
9
10
  import log from "loglevel";
10
11
 
@@ -13,7 +14,7 @@ import log from "loglevel";
13
14
  * @param {string} title
14
15
  * @param {Record<string,import("stac-ts").StacAsset>} assets
15
16
  * @param {import("stac-ts").StacItem } item
16
- * @param {import("ol/layer/WebGLTile").Style} [style]
17
+ * @param {import("@/types").EodashStyleJson} [style]
17
18
  * @param {Record<string, unknown>} [layerConfig]
18
19
  * @param {Record<string, unknown>} [layerDatetime]
19
20
  * @param {object | null} [extraProperties]
@@ -33,6 +34,11 @@ export async function createLayersFromAssets(
33
34
  let geoTIFFSources = [];
34
35
  /** @type {number|null} */
35
36
  let geoTIFFIdx = null;
37
+ // let geoJsonLayers = [];
38
+ let geoJsonIdx = 0;
39
+
40
+ const geoJsonSources = [];
41
+ let geoJsonRoles = {};
36
42
 
37
43
  for (const [idx, ast] of Object.keys(assets).entries()) {
38
44
  // register projection if exists
@@ -41,15 +47,18 @@ export async function createLayersFromAssets(
41
47
  assets[ast]?.["proj:epsg"] || assets[ast]?.["eodash:proj4_def"]
42
48
  );
43
49
  await registerProjection(assetProjection);
44
-
45
- if (assets[ast]?.type === "application/geo+json" || assets[ast]?.type === "application/vnd.flatgeobuf") {
50
+ if (assets[ast]?.type === "application/geo+json") {
51
+ geoJsonSources.push(assets[ast].href);
52
+ geoJsonIdx = idx;
53
+ extractRoles(geoJsonRoles, assets[ast]);
54
+ } else if (assets[ast]?.type === "application/vnd.flatgeobuf") {
46
55
  const assetId = createAssetID(collectionId, item.id, idx);
47
- const sourceType = assets[ast]?.type === "application/geo+json" ? "GeoJSON" : "FlatGeoBuf";
48
- log.debug(`Creating Vector layer from ${sourceType}`, assetId);
56
+ log.debug(`Creating Vector layer from FlatGeoBuf`, assetId);
57
+
49
58
  const layer = {
50
59
  type: "Vector",
51
60
  source: {
52
- type: sourceType,
61
+ type: "FlatGeoBuf",
53
62
  url: assets[ast].href,
54
63
  format: "GeoJSON",
55
64
  },
@@ -66,6 +75,23 @@ export async function createLayersFromAssets(
66
75
  },
67
76
  ...(!style?.variables && { style }),
68
77
  };
78
+ // add tooltip interaction if style has tooltip
79
+ if (style?.tooltip) {
80
+ // @ts-expect-error no type for eox-map layer
81
+ layer.interactions = [
82
+ {
83
+ type: "select",
84
+ options: {
85
+ id: (Math.random() * 10000).toFixed() + "_selectInteraction",
86
+ condition: "pointermove",
87
+ style: {
88
+ "stroke-color": "#335267",
89
+ "stroke-width": 4,
90
+ },
91
+ },
92
+ },
93
+ ];
94
+ }
69
95
 
70
96
  extractRoles(layer.properties, assets[ast]);
71
97
 
@@ -78,6 +104,36 @@ export async function createLayersFromAssets(
78
104
  }
79
105
  }
80
106
 
107
+ if (geoJsonSources.length) {
108
+ const assetId = createAssetID(collectionId, item.id, geoJsonIdx);
109
+ log.debug(`Creating Vector layer from GeoJsons`, assetId);
110
+
111
+ const layer = {
112
+ type: "Vector",
113
+ source: {
114
+ type: "Vector",
115
+ url: await mergeGeojsons(geoJsonSources),
116
+ format: "GeoJSON",
117
+ },
118
+ properties: {
119
+ ...geoJsonRoles,
120
+ id: assetId,
121
+ title,
122
+ layerDatetime,
123
+ ...(layerConfig && {
124
+ layerConfig: {
125
+ ...layerConfig,
126
+ style,
127
+ },
128
+ }),
129
+ },
130
+ ...(!style?.variables && { style }),
131
+ };
132
+
133
+ layer.properties = { ...layer.properties, ...(extraProperties ?? {}) };
134
+
135
+ jsonArray.push(layer);
136
+ }
81
137
  if (geoTIFFSources.length && typeof geoTIFFIdx === "number") {
82
138
  const geotiffSourceID = collectionId + ";:;GeoTIFF";
83
139
  log.debug("Creating WebGLTile layer from GeoTIFF", geotiffSourceID);
@@ -1,6 +1,7 @@
1
1
  import { toAbsolute } from "stac-js/src/http.js";
2
2
  import axios from "@/plugins/axios";
3
3
  import log from "loglevel";
4
+ import { getStyleVariablesState } from "./triggers.js";
4
5
 
5
6
  /** @param {import("stac-ts").StacLink[]} [links] */
6
7
  export function generateFeatures(links) {
@@ -39,13 +40,24 @@ export function generateFeatures(links) {
39
40
  /**
40
41
  * Sperates and extracts layerConfig (jsonform schema & legend) from a style json
41
42
  *
42
- * @param { import("ol/layer/WebGLTile").Style & { jsonform?: Record<string,any> } & { legend?: Record<string,any> } } [style] */
43
- export function extractLayerConfig(style) {
43
+ * @param {string} collectionId
44
+ * @param { import("@/types").EodashStyleJson} [style]
45
+ * */
46
+ export function extractLayerConfig(collectionId, style) {
47
+ if (!style) {
48
+ return { layerConfig: undefined, style: undefined };
49
+ }
50
+ style = { ...style };
51
+
52
+ if (Object.keys(style.variables ?? {}).length) {
53
+ style.variables = getStyleVariablesState(collectionId, style.variables);
54
+ }
55
+
44
56
  /** @type {Record<string,unknown> | undefined} */
45
57
  let layerConfig = undefined;
58
+
46
59
  if (style?.jsonform) {
47
60
  layerConfig = { schema: style.jsonform, type: "style" };
48
- style = { ...style };
49
61
  delete style.jsonform;
50
62
  if (style?.legend) {
51
63
  layerConfig.legend = style.legend;
@@ -124,7 +136,7 @@ export const fetchStyle = async (item, itemUrl) => {
124
136
  url = toAbsolute(styleLink.href, itemUrl);
125
137
  }
126
138
 
127
- /** @type {import("ol/layer/WebGLTile").Style & {jsonform?:Record<string,any>}} */
139
+ /** @type {import("@/types").EodashStyleJson} */
128
140
  const styleJson = await axios.get(url).then((resp) => resp.data);
129
141
 
130
142
  log.debug("fetched styles JSON", JSON.parse(JSON.stringify(styleJson)));
@@ -200,8 +212,9 @@ export const extractLayerDatetime = (links, currentStep) => {
200
212
  controlValues,
201
213
  currentStep,
202
214
  slider: true,
215
+ navigation: true,
203
216
  play: false,
204
- displayFormat: "DD MMMM YYYY",
217
+ displayFormat: "DD.MM.YYYY HH:MM",
205
218
  };
206
219
  };
207
220
 
@@ -373,3 +386,33 @@ export const removeUnneededProperties = (layers) => {
373
386
  });
374
387
  return cloned;
375
388
  };
389
+
390
+ /**
391
+ * @param {string[]} geojsonUrls
392
+ */
393
+ export async function mergeGeojsons(geojsonUrls) {
394
+ if (!geojsonUrls.length) {
395
+ return undefined;
396
+ }
397
+ if (geojsonUrls.length === 1) {
398
+ return geojsonUrls[0];
399
+ }
400
+
401
+ const merged = {
402
+ type: "FeatureCollection",
403
+ /** @type {import("ol").Feature[]} */
404
+ features: [],
405
+ };
406
+ await Promise.all(
407
+ geojsonUrls.map((url) =>
408
+ axios.get(url).then((resp) => {
409
+ const geojson = resp.data;
410
+ merged.features.push(...(geojson.features ?? []));
411
+ }),
412
+ ),
413
+ );
414
+
415
+ return encodeURI(
416
+ "data:application/json;charset=utf-8," + JSON.stringify(merged),
417
+ );
418
+ }