@eodash/eodash 5.7.0 → 5.8.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/EodashOverlay.vue +27 -4
- package/core/client/composables/DefineEodash.js +0 -1
- package/core/client/composables/DefineWidgets.js +3 -1
- package/core/client/eodashSTAC/EodashCollection.js +87 -24
- package/core/client/eodashSTAC/cql.js +64 -0
- package/core/client/eodashSTAC/createLayers.js +353 -187
- package/core/client/eodashSTAC/helpers.js +694 -110
- package/core/client/eodashSTAC/mosaic.js +422 -0
- package/core/client/plugins/axios.js +31 -1
- package/core/client/store/actions.js +1 -1
- package/core/client/store/stac.js +54 -4
- package/core/client/store/states.js +20 -2
- package/core/client/types.ts +152 -28
- package/core/client/utils/bands-editor/exampleSchema.json +50 -50
- package/core/client/utils/states.js +10 -0
- package/dist/client/{DashboardLayout-kRsmsNW5.js → DashboardLayout-DEs4f_Vy.js} +2 -2
- package/dist/client/{DynamicWebComponent-CnKhYo0K.js → DynamicWebComponent-PvnV88BA.js} +1 -1
- package/dist/client/EodashChart-D-3AGKZY.js +260 -0
- package/dist/client/{EodashDatePicker-CMPDT-ce.js → EodashDatePicker-Dm_goZzs.js} +3 -3
- package/dist/client/{EodashItemFilter-BpdA8QQa.js → EodashItemFilter-CJy3zYzD.js} +2 -1
- package/dist/client/{EodashLayerControl-BHpDA4_0.js → EodashLayerControl-rL8UnpkA.js} +55 -33
- package/dist/client/{EodashLayoutSwitcher-B1fRUt7G.js → EodashLayoutSwitcher-ZRlESI9O.js} +3 -3
- package/dist/client/{EodashMapBtns-Cpned0tc.js → EodashMapBtns-CG7u2Aq8.js} +227 -112
- package/dist/client/EodashStacInfo-CJhhxthD.js +169 -0
- package/dist/client/{EodashTools-1zHz26gv.js → EodashTools-CWyK8QJT.js} +4 -4
- package/dist/client/{ExportState-DbOm8hBI.js → ExportState-BXhy5TOU.js} +20 -174
- package/dist/client/{Footer-BKg-VVkj.js → Footer-DZPvnhcT.js} +1 -1
- package/dist/client/{Header-DCrwCvmY.js → Header-CiGsDE_a.js} +2 -2
- package/dist/client/{MobileLayout-vWSHpluo.js → MobileLayout-BJHW7x5V.js} +2 -2
- package/dist/client/{PopUp-9uimfK49.js → PopUp-7_XnhvCc.js} +4 -168
- package/dist/client/{ProcessList-CTTIZa06.js → ProcessList-LL_UCbvc.js} +5 -5
- package/dist/client/VDivider-DWYM0WUr.js +168 -0
- package/dist/client/{VImg-CrmB76ZY.js → VImg-B75dgw2K.js} +2 -2
- package/dist/client/{VMain-OKZNpcEG.js → VMain-DvMmOL4f.js} +1 -1
- package/dist/client/{VTooltip-CJw2FyWk.js → VTooltip-ClWHUmWL.js} +2 -2
- package/dist/client/{WidgetsContainer-BaWOnE5R.js → WidgetsContainer-BqaWs4ch.js} +1 -1
- package/dist/client/{asWebComponent-BHWpMuE3.js → asWebComponent-IZanwL-A.js} +677 -379
- package/dist/client/{async-DSKj6g1f.js → async-CiNIOBVz.js} +31 -29
- package/dist/client/{create-layers-config-CBoYedqB.js → create-layers-config-3S3y_kZg.js} +17 -17
- package/dist/client/dialog-transition-c4ZSnzac.js +170 -0
- package/dist/client/eo-dash.js +1 -1
- package/dist/client/{forwardRefs-DH51zPUr.js → forwardRefs-B-c1_6yo.js} +8 -87
- package/dist/client/{handling-BrcDDlgS.js → handling-NvY8Csry.js} +3 -4
- package/dist/client/{helpers-DjZVl_WF.js → helpers-BFuh19CP.js} +1094 -194
- package/dist/client/{index-1JKE68n3.js → index-1wMAyuNL.js} +219 -67
- package/dist/client/{index-CSG_JoOA.js → index-B8jGJSTA.js} +62 -56
- package/dist/client/{index-Cu3-13Xg.js → index-BKQQJkhy.js} +167 -61
- package/dist/client/index-D0jUyol8.js +3167 -0
- package/dist/client/{index-CUjl-ZsI.js → index-KGxz5Egv.js} +2 -2
- package/dist/client/mosaic-vHvSuih6.js +459 -0
- package/dist/client/templates.js +251 -121
- package/dist/client/{transition-OHcz5Qq1.js → transition-BkyUsZh_.js} +1 -1
- package/dist/node/cli.js +5 -5
- package/dist/node/types.d.ts +4 -0
- package/dist/types/core/client/composables/DefineEodash.d.ts +1 -1
- package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +57 -25
- package/dist/types/core/client/eodashSTAC/cql.d.ts +15 -0
- package/dist/types/core/client/eodashSTAC/createLayers.d.ts +42 -23
- package/dist/types/core/client/eodashSTAC/helpers.d.ts +118 -19
- package/dist/types/core/client/eodashSTAC/mosaic.d.ts +56 -0
- package/dist/types/core/client/store/stac.d.ts +38 -8
- package/dist/types/core/client/store/states.d.ts +24 -2
- package/dist/types/core/client/types.d.ts +128 -24
- package/dist/types/core/client/utils/states.d.ts +12 -0
- package/dist/types/templates/baseConfig.d.ts +1 -100
- package/dist/types/templates/compare.d.ts +32 -3
- package/dist/types/templates/expert.d.ts +18 -0
- package/dist/types/templates/explore.d.ts +10 -1
- package/dist/types/templates/lite.d.ts +11 -0
- package/dist/types/widgets/EodashChart.vue.d.ts +5 -3
- package/dist/types/widgets/EodashItemCatalog/index.vue.d.ts +129 -2
- package/dist/types/widgets/EodashItemCatalog/methods/filters.d.ts +28 -6
- package/dist/types/widgets/EodashItemCatalog/methods/handlers.d.ts +17 -4
- package/dist/types/widgets/EodashItemCatalog/methods/map.d.ts +16 -4
- package/dist/types/widgets/EodashLayerControl.vue.d.ts +35 -16
- package/dist/types/widgets/EodashMap/EodashMapBtns.vue.d.ts +14 -10
- package/dist/types/widgets/EodashMap/index.vue.d.ts +86 -37
- package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +1 -1
- package/dist/types/widgets/EodashMap/methods/index.d.ts +5 -1
- package/dist/types/widgets/EodashMap/methods/use-map-loading.d.ts +1 -0
- package/dist/types/widgets/EodashProcess/index.vue.d.ts +5 -3
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.d.ts +1 -1
- package/dist/types/widgets/EodashProcess/states.d.ts +1 -1
- package/dist/types/widgets/EodashStacInfo.vue.d.ts +20 -0
- package/dist/types/widgets/EodashTimeSlider/index.vue.d.ts +20 -0
- package/dist/types/widgets/EodashTimeSlider/methods/index.d.ts +3 -8
- package/dist/types/widgets/EodashTimeSlider/types.d.ts +6 -16
- package/dist/types/widgets/EodashTools.vue.d.ts +5 -5
- package/package.json +34 -34
- package/templates/baseConfig.js +37 -6
- package/templates/compare.js +61 -7
- package/templates/expert.js +24 -2
- package/templates/explore.js +12 -5
- package/templates/lite.js +13 -0
- package/widgets/EodashChart.vue +162 -21
- package/widgets/EodashItemCatalog/index.vue +363 -35
- package/widgets/EodashItemCatalog/methods/filters.js +134 -70
- package/widgets/EodashItemCatalog/methods/handlers.js +113 -19
- package/widgets/EodashItemCatalog/methods/map.js +141 -28
- package/widgets/EodashLayerControl.vue +51 -25
- package/widgets/EodashMap/EodashMapBtns.vue +109 -48
- package/widgets/EodashMap/index.vue +91 -105
- package/widgets/EodashMap/methods/btns.js +64 -31
- package/widgets/EodashMap/methods/create-layers-config.js +16 -16
- package/widgets/EodashMap/methods/index.js +71 -8
- package/widgets/EodashMap/methods/use-map-loading.js +58 -0
- package/widgets/EodashProcess/index.vue +136 -16
- package/widgets/EodashProcess/methods/composables.js +13 -0
- package/widgets/EodashProcess/methods/outputs.js +0 -1
- package/widgets/EodashProcess/methods/utils.js +29 -27
- package/widgets/EodashProcess/states.js +1 -1
- package/widgets/EodashStacInfo.vue +64 -2
- package/widgets/EodashTimeSlider/index.vue +58 -2
- package/widgets/EodashTimeSlider/methods/index.js +5 -48
- package/widgets/EodashTimeSlider/types.ts +7 -17
- package/widgets/ExportState.vue +13 -4
- package/dist/client/EodashChart-CLDqE93C.js +0 -144
- package/dist/client/EodashStacInfo-BQspAHKH.js +0 -107
- package/dist/client/index-5Jhsa8Xe.js +0 -570
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { useOnLayersUpdate } from "@/composables";
|
|
2
|
-
import { mapEl } from "@/store/states";
|
|
3
2
|
import { onMounted, onUnmounted } from "vue";
|
|
3
|
+
import { createOnSelectHandler } from "./handlers";
|
|
4
|
+
import { tooltipAdapter } from "@/store/states";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
7
8
|
* @param {import("@/types").GeoJsonFeature[]} features
|
|
9
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} mapElement
|
|
10
|
+
* @param {string[] | undefined} hoverProperties
|
|
11
|
+
* @param {object} [stacItemsStyle]
|
|
12
|
+
* @param {object} [stacItemsInteractionStyle]
|
|
8
13
|
*/
|
|
9
|
-
export function renderItemsFeatures(
|
|
14
|
+
export function renderItemsFeatures(
|
|
15
|
+
features,
|
|
16
|
+
mapElement,
|
|
17
|
+
hoverProperties,
|
|
18
|
+
stacItemsStyle,
|
|
19
|
+
stacItemsInteractionStyle,
|
|
20
|
+
) {
|
|
21
|
+
const currentMap = mapElement.value;
|
|
10
22
|
let analysisLayers =
|
|
11
23
|
/** @type {import("@eox/map/src/layers").EOxLayerTypeGroup} */ (
|
|
12
|
-
|
|
24
|
+
currentMap?.layers?.find((l) => l.properties?.id === "AnalysisGroup")
|
|
13
25
|
);
|
|
14
|
-
if (!
|
|
26
|
+
if (!currentMap || !features) {
|
|
15
27
|
return;
|
|
16
28
|
}
|
|
17
29
|
if (!analysisLayers) {
|
|
@@ -23,9 +35,9 @@ export function renderItemsFeatures(features) {
|
|
|
23
35
|
},
|
|
24
36
|
layers: [],
|
|
25
37
|
};
|
|
26
|
-
|
|
38
|
+
currentMap.layers = [...currentMap.layers, analysisLayers];
|
|
27
39
|
}
|
|
28
|
-
|
|
40
|
+
/** @type {import("@eox/map/src/layers").EOxLayerType<"Vector","Vector">} */
|
|
29
41
|
const stacItemsLayer = {
|
|
30
42
|
type: "Vector",
|
|
31
43
|
properties: {
|
|
@@ -40,8 +52,9 @@ export function renderItemsFeatures(features) {
|
|
|
40
52
|
JSON.stringify({ type: "FeatureCollection", features }),
|
|
41
53
|
),
|
|
42
54
|
format: "GeoJSON",
|
|
55
|
+
projection: "EPSG:4326",
|
|
43
56
|
},
|
|
44
|
-
style: {
|
|
57
|
+
style: stacItemsStyle || {
|
|
45
58
|
"fill-color": "transparent",
|
|
46
59
|
"stroke-color": "#003170",
|
|
47
60
|
},
|
|
@@ -49,35 +62,47 @@ export function renderItemsFeatures(features) {
|
|
|
49
62
|
{
|
|
50
63
|
type: "select",
|
|
51
64
|
options: {
|
|
52
|
-
id: "stac-
|
|
65
|
+
id: "stac-item-hover",
|
|
53
66
|
condition: "pointermove",
|
|
54
|
-
|
|
67
|
+
tooltip: hoverProperties?.length,
|
|
68
|
+
style: stacItemsInteractionStyle || {
|
|
55
69
|
"stroke-color": "white",
|
|
56
70
|
"stroke-width": 3,
|
|
57
71
|
},
|
|
58
72
|
},
|
|
59
73
|
},
|
|
74
|
+
{
|
|
75
|
+
type: "select",
|
|
76
|
+
options: {
|
|
77
|
+
id: "stac-items",
|
|
78
|
+
condition: "click",
|
|
79
|
+
tooltip: false,
|
|
80
|
+
style: stacItemsInteractionStyle || {
|
|
81
|
+
"stroke-color": "#003047",
|
|
82
|
+
"stroke-width": 3.2,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
60
86
|
],
|
|
61
87
|
};
|
|
62
88
|
const exists = analysisLayers.layers.some(
|
|
63
|
-
(l) => l.properties?.id ===
|
|
89
|
+
(l) => l.properties?.id === stacItemsLayer.properties?.id,
|
|
64
90
|
);
|
|
65
91
|
if (exists) {
|
|
66
|
-
|
|
67
|
-
mapEl.value.addOrUpdateLayer(stacItemsLayer);
|
|
92
|
+
currentMap.addOrUpdateLayer(stacItemsLayer);
|
|
68
93
|
return;
|
|
69
94
|
} else {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
mapEl.value.layers = [...mapEl.value.layers];
|
|
95
|
+
analysisLayers.layers.unshift(stacItemsLayer);
|
|
96
|
+
currentMap.layers = [...currentMap.layers];
|
|
73
97
|
}
|
|
74
98
|
}
|
|
75
99
|
|
|
76
100
|
/**
|
|
77
101
|
* @param {import("vue").Ref<any>} itemFilter
|
|
78
102
|
* @param {boolean} bboxFilter
|
|
103
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} mapElement
|
|
79
104
|
*/
|
|
80
|
-
export const useSearchOnMapMove = (itemFilter, bboxFilter) => {
|
|
105
|
+
export const useSearchOnMapMove = (itemFilter, bboxFilter, mapElement) => {
|
|
81
106
|
if (!bboxFilter) {
|
|
82
107
|
return;
|
|
83
108
|
}
|
|
@@ -86,58 +111,146 @@ export const useSearchOnMapMove = (itemFilter, bboxFilter) => {
|
|
|
86
111
|
const handler = () => {
|
|
87
112
|
clearTimeout(timeout);
|
|
88
113
|
timeout = setTimeout(() => {
|
|
114
|
+
if (mapElement.value?.projection == "globe") {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
89
117
|
itemFilter.value?.search();
|
|
90
|
-
},
|
|
118
|
+
}, 500);
|
|
91
119
|
};
|
|
92
120
|
onMounted(() => {
|
|
93
|
-
|
|
121
|
+
mapElement.value?.map.on("moveend", handler);
|
|
94
122
|
});
|
|
95
123
|
onUnmounted(() => {
|
|
96
|
-
|
|
124
|
+
mapElement.value?.map.un("moveend", handler);
|
|
97
125
|
});
|
|
98
126
|
};
|
|
99
127
|
/**
|
|
100
128
|
*
|
|
101
129
|
* @param {import("vue").Ref<import("@/types").GeoJsonFeature[]>} currentItems
|
|
130
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} mapElement
|
|
131
|
+
* @param {string[] | undefined} hoverProperties
|
|
132
|
+
* @param {object} [stacItemsStyle]
|
|
133
|
+
* @param {object} [stacItemsInteractionStyle]
|
|
102
134
|
*/
|
|
103
|
-
export const useRenderItemsFeatures = (
|
|
135
|
+
export const useRenderItemsFeatures = (
|
|
136
|
+
currentItems,
|
|
137
|
+
mapElement,
|
|
138
|
+
hoverProperties,
|
|
139
|
+
stacItemsStyle,
|
|
140
|
+
stacItemsInteractionStyle,
|
|
141
|
+
) => {
|
|
104
142
|
onMounted(() => {
|
|
105
|
-
renderItemsFeatures(
|
|
143
|
+
renderItemsFeatures(
|
|
144
|
+
currentItems.value,
|
|
145
|
+
mapElement,
|
|
146
|
+
hoverProperties,
|
|
147
|
+
stacItemsStyle,
|
|
148
|
+
stacItemsInteractionStyle,
|
|
149
|
+
);
|
|
106
150
|
});
|
|
107
151
|
|
|
108
152
|
useOnLayersUpdate(() => {
|
|
109
153
|
// consider cases where this is not needed
|
|
110
|
-
renderItemsFeatures(
|
|
154
|
+
renderItemsFeatures(
|
|
155
|
+
currentItems.value,
|
|
156
|
+
mapElement,
|
|
157
|
+
hoverProperties,
|
|
158
|
+
stacItemsStyle,
|
|
159
|
+
stacItemsInteractionStyle,
|
|
160
|
+
);
|
|
111
161
|
});
|
|
112
162
|
};
|
|
163
|
+
/**
|
|
164
|
+
* Registers a tooltip adapter that displays item properties when hovering over map features.
|
|
165
|
+
* @param {string[]} [hoverProperties]
|
|
166
|
+
*/
|
|
167
|
+
export function useHoverTooltip(hoverProperties) {
|
|
168
|
+
/**
|
|
169
|
+
* @param {*} val
|
|
170
|
+
*/
|
|
171
|
+
const formatValue = (val) => {
|
|
172
|
+
if (typeof val === "number") {
|
|
173
|
+
return val.toFixed(0);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (typeof val === "string") {
|
|
177
|
+
// Attempt to parse as date if string looks like ISO date
|
|
178
|
+
if (val.length > 9 && /\d{4}-\d{2}-\d{2}/.test(val)) {
|
|
179
|
+
const timestamp = Date.parse(val);
|
|
180
|
+
if (!isNaN(timestamp)) {
|
|
181
|
+
return new Date(timestamp).toUTCString();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return val;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* @param {string} key
|
|
189
|
+
*/
|
|
190
|
+
const formatKey = (key) => {
|
|
191
|
+
let formattedKey = key;
|
|
192
|
+
if (key.includes(":")) {
|
|
193
|
+
formattedKey = key.split(":")[1];
|
|
194
|
+
}
|
|
195
|
+
return formattedKey
|
|
196
|
+
.replace(/_/g, " ")
|
|
197
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
198
|
+
};
|
|
199
|
+
onMounted(() => {
|
|
200
|
+
tooltipAdapter.value = ({ key, value }) => {
|
|
201
|
+
if (hoverProperties && hoverProperties.includes(key)) {
|
|
202
|
+
return { key: formatKey(key), value: formatValue(value) };
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
onUnmounted(() => {
|
|
208
|
+
tooltipAdapter.value = null;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
113
212
|
/**
|
|
114
213
|
*
|
|
115
214
|
* @param {import("vue").Ref<any>} itemfilterEl
|
|
215
|
+
* @param {ReturnType< typeof import("@/store/stac").useSTAcStore>} store
|
|
216
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} mapElement
|
|
217
|
+
* @param {boolean} enableCompare
|
|
116
218
|
*/
|
|
117
|
-
export function
|
|
219
|
+
export function useRenderOnFeatureClick(
|
|
220
|
+
itemfilterEl,
|
|
221
|
+
store,
|
|
222
|
+
mapElement,
|
|
223
|
+
enableCompare,
|
|
224
|
+
) {
|
|
225
|
+
const onSelectItem = createOnSelectHandler(store, enableCompare, mapElement);
|
|
118
226
|
/**
|
|
119
227
|
*
|
|
120
228
|
* @param {CustomEvent} evt
|
|
121
229
|
*/
|
|
122
230
|
const handler = (evt) => {
|
|
231
|
+
if (evt.detail.originalEvent.type !== "click") {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
123
234
|
const itemId = evt.detail?.feature?.getId();
|
|
124
235
|
if (!itemId) {
|
|
125
236
|
return;
|
|
126
237
|
}
|
|
127
|
-
const item = itemfilterEl.value.
|
|
238
|
+
const item = itemfilterEl.value.results?.find(
|
|
128
239
|
//@ts-expect-error todo
|
|
129
|
-
(r) => r
|
|
240
|
+
(r) => r?.id === itemId,
|
|
130
241
|
);
|
|
242
|
+
|
|
131
243
|
if (item) {
|
|
132
|
-
|
|
244
|
+
onSelectItem(new CustomEvent("select", { detail: item }));
|
|
133
245
|
}
|
|
134
246
|
};
|
|
247
|
+
|
|
135
248
|
onMounted(() => {
|
|
136
249
|
//@ts-expect-error todo
|
|
137
|
-
|
|
250
|
+
mapElement.value?.addEventListener("select", handler);
|
|
138
251
|
});
|
|
139
252
|
onUnmounted(() => {
|
|
140
253
|
//@ts-expect-error todo
|
|
141
|
-
|
|
254
|
+
mapElement.value?.removeEventListener("select", handler);
|
|
142
255
|
});
|
|
143
256
|
}
|
|
@@ -5,37 +5,49 @@
|
|
|
5
5
|
:key="mapElement"
|
|
6
6
|
v-bind="config"
|
|
7
7
|
:for="mapElement"
|
|
8
|
+
.colormapRegistry="colormapRegistry"
|
|
9
|
+
.showLayerZoomState="true"
|
|
8
10
|
.customEditorInterfaces="bandsEditorInterface"
|
|
9
11
|
@datetime:updated="debouncedHandleDateTime"
|
|
10
12
|
toolsAsList="true"
|
|
11
13
|
ref="eoxLayercontrol"
|
|
12
14
|
@layerConfig:change="onLayerConfigChange"
|
|
13
15
|
>
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
<span
|
|
17
|
+
slot="layerstitle"
|
|
18
|
+
class="d-flex justify-space-between ma-2 pa-2 flex-shrink-0"
|
|
19
|
+
>
|
|
20
|
+
<h4 v-if="title">{{ title }}</h4>
|
|
21
|
+
<EodashLayoutSwitcher
|
|
22
|
+
v-if="enableLayoutSwitcher"
|
|
23
|
+
:target="layoutTarget"
|
|
24
|
+
:icon="layoutIcon"
|
|
25
|
+
/>
|
|
26
|
+
</span>
|
|
21
27
|
</eox-layercontrol>
|
|
22
28
|
</span>
|
|
23
29
|
</template>
|
|
24
30
|
<script setup>
|
|
25
31
|
import "color-legend-element";
|
|
26
32
|
import "@eox/timecontrol";
|
|
27
|
-
import { computed, ref
|
|
33
|
+
import { computed, ref } from "vue";
|
|
28
34
|
import { mapEl, mapCompareEl } from "@/store/states";
|
|
29
|
-
import { getColFromLayer } from "@/eodashSTAC/helpers";
|
|
30
35
|
import {
|
|
31
36
|
eodashCollections,
|
|
32
37
|
eodashCompareCollections,
|
|
33
38
|
layerControlFormValue,
|
|
34
39
|
layerControlFormValueCompare,
|
|
35
40
|
} from "@/utils/states";
|
|
41
|
+
import {
|
|
42
|
+
getColFromLayer,
|
|
43
|
+
updateGeoZarrBands,
|
|
44
|
+
updateLayerUrl,
|
|
45
|
+
} from "@/eodashSTAC/helpers";
|
|
36
46
|
import { storeToRefs } from "pinia";
|
|
37
47
|
import { useSTAcStore } from "@/store/stac";
|
|
38
48
|
import { bandsEditorInterface } from "@/utils/bands-editor";
|
|
49
|
+
import EodashLayoutSwitcher from "^/EodashLayoutSwitcher.vue";
|
|
50
|
+
import { mdiViewDashboard } from "@mdi/js";
|
|
39
51
|
import { useEmitLayersUpdate } from "@/composables";
|
|
40
52
|
|
|
41
53
|
if (!customElements.get("eox-layercontrol")) {
|
|
@@ -46,22 +58,39 @@ if (!customElements.get("eox-jsonform")) {
|
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
const props = defineProps({
|
|
61
|
+
/** Which map instance this control is bound to. Use `"second"` in a compare-mode layout. */
|
|
49
62
|
map: {
|
|
50
63
|
/** @type {import("vue").PropType<"first" | "second">} */
|
|
51
64
|
//@ts-expect-error todo
|
|
52
65
|
type: String,
|
|
53
66
|
default: "first",
|
|
54
67
|
},
|
|
68
|
+
/** Tool tabs shown inside `eox-layercontrol`. Remove entries to hide individual tabs. */
|
|
55
69
|
tools: {
|
|
56
|
-
type: Array,
|
|
70
|
+
type: /** @type {import("vue").PropType<string[]>} */ (Array),
|
|
57
71
|
default: () => ["datetime", "info", "config", "legend", "opacity"],
|
|
58
72
|
},
|
|
73
|
+
/** Heading rendered above the layer list. Set to `false` to hide it. */
|
|
59
74
|
title: {
|
|
60
|
-
type:
|
|
75
|
+
type: /** @type {import("vue").PropType<string | false>} */ ([
|
|
76
|
+
String,
|
|
77
|
+
Boolean,
|
|
78
|
+
]),
|
|
61
79
|
default: "Layers",
|
|
62
80
|
},
|
|
81
|
+
/** CSS custom-property overrides forwarded to the underlying `eox-layercontrol` element via its `style` attribute. */
|
|
63
82
|
cssVars: {
|
|
64
|
-
type:
|
|
83
|
+
type: /** @type {import("vue").PropType<Record<string, string>>} */ (
|
|
84
|
+
Object
|
|
85
|
+
),
|
|
86
|
+
default: {},
|
|
87
|
+
},
|
|
88
|
+
layoutIcon: {
|
|
89
|
+
type: String,
|
|
90
|
+
default: mdiViewDashboard,
|
|
91
|
+
},
|
|
92
|
+
layoutTarget: {
|
|
93
|
+
type: String,
|
|
65
94
|
},
|
|
66
95
|
});
|
|
67
96
|
|
|
@@ -70,7 +99,12 @@ const config = {
|
|
|
70
99
|
style: props.cssVars,
|
|
71
100
|
};
|
|
72
101
|
|
|
73
|
-
const
|
|
102
|
+
const enableLayoutSwitcher = computed(
|
|
103
|
+
() => !!props.layoutTarget && !!props.layoutIcon,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const { selectedCompareStac, selectedStac, colormapRegistry } =
|
|
107
|
+
storeToRefs(useSTAcStore());
|
|
74
108
|
|
|
75
109
|
const showControls = computed(() => {
|
|
76
110
|
if (props.map === "second") {
|
|
@@ -83,23 +117,12 @@ const eodashCols =
|
|
|
83
117
|
props.map === "second" ? eodashCompareCollections : eodashCollections;
|
|
84
118
|
const mapElement = props.map === "second" ? mapCompareEl : mapEl;
|
|
85
119
|
|
|
86
|
-
/** @type { import("vue").Ref<
|
|
120
|
+
/** @type { import("vue").Ref<import("@eox/layercontrol").EOxLayerControl | null>} */
|
|
87
121
|
const eoxLayercontrol = ref(null);
|
|
88
122
|
|
|
89
|
-
// eox-timecontrol re-fires datetime:updated after layer reassignment;
|
|
90
|
-
// dedupe by (collectionId, datetime)
|
|
91
|
-
const processedDatetimes = new Map();
|
|
92
|
-
watch([selectedStac, selectedCompareStac], () => processedDatetimes.clear());
|
|
93
|
-
|
|
94
123
|
/** @param {CustomEvent<{layer:import('ol/layer').Layer; datetime:string;}>} evt */
|
|
95
124
|
const handleDatetimeUpdate = async (evt) => {
|
|
96
125
|
const { layer, datetime } = evt.detail;
|
|
97
|
-
const collectionId = layer.get("id")?.split(";:;")[0] ?? layer.get("id");
|
|
98
|
-
if (processedDatetimes.get(collectionId) === datetime) return;
|
|
99
|
-
// First event per collection is eox-timecontrol's mount echo.
|
|
100
|
-
const isFirstEvent = !processedDatetimes.has(collectionId);
|
|
101
|
-
processedDatetimes.set(collectionId, datetime);
|
|
102
|
-
if (isFirstEvent) return;
|
|
103
126
|
|
|
104
127
|
const ec = await getColFromLayer(eodashCols, layer);
|
|
105
128
|
|
|
@@ -155,6 +178,9 @@ const debouncedHandleDateTime = (evt) => {
|
|
|
155
178
|
* @param {Event & {detail:{layer:import("ol/layer").Layer;jsonformValue:Record<string,any>}}} evt
|
|
156
179
|
*/
|
|
157
180
|
const onLayerConfigChange = (evt) => {
|
|
181
|
+
updateGeoZarrBands(evt.detail.layer, evt.detail.jsonformValue);
|
|
182
|
+
updateLayerUrl(evt.detail.layer, evt.detail.jsonformValue);
|
|
183
|
+
|
|
158
184
|
if (props.map === "second") {
|
|
159
185
|
layerControlFormValueCompare.value = evt.detail.jsonformValue;
|
|
160
186
|
} else {
|
|
@@ -5,30 +5,28 @@
|
|
|
5
5
|
class="primary small circle small-elevate"
|
|
6
6
|
@click="onMapZoomIn"
|
|
7
7
|
>
|
|
8
|
-
<i class="small"
|
|
9
|
-
|
|
8
|
+
<i class="small">
|
|
9
|
+
<svg viewBox="0 0 24 24"><path :d="mdiPlus"></path></svg>
|
|
10
10
|
</i>
|
|
11
11
|
<div class="tooltip left">Zoom in</div>
|
|
12
12
|
</button>
|
|
13
|
-
|
|
14
13
|
<button
|
|
15
14
|
v-if="enableZoom && !isGlobe"
|
|
16
15
|
class="primary small circle small-elevate"
|
|
17
16
|
@click="onMapZoomOut"
|
|
18
17
|
>
|
|
19
|
-
<i class="small"
|
|
20
|
-
|
|
18
|
+
<i class="small">
|
|
19
|
+
<svg viewBox="0 0 24 24"><path :d="mdiMinus"></path></svg>
|
|
21
20
|
</i>
|
|
22
21
|
<div class="tooltip left">Zoom out</div>
|
|
23
22
|
</button>
|
|
24
|
-
|
|
25
23
|
<button
|
|
26
24
|
v-if="exportMap"
|
|
27
25
|
class="primary small circle small-elevate"
|
|
28
26
|
@click="showMapState = !showMapState"
|
|
29
27
|
>
|
|
30
|
-
<i class="small"
|
|
31
|
-
|
|
28
|
+
<i class="small">
|
|
29
|
+
<svg viewBox="0 0 24 24"><path :d="mdiMapPlus"></path></svg>
|
|
32
30
|
</i>
|
|
33
31
|
<div class="tooltip left">Extract storytelling configuration</div>
|
|
34
32
|
</button>
|
|
@@ -39,8 +37,8 @@
|
|
|
39
37
|
class="primary small circle small-elevate"
|
|
40
38
|
@click="changeMapProjection(availableMapProjection)"
|
|
41
39
|
>
|
|
42
|
-
<i class="small"
|
|
43
|
-
|
|
40
|
+
<i class="small">
|
|
41
|
+
<svg viewBox="0 0 24 24"><path :d="mdiEarthBox"></path></svg>
|
|
44
42
|
</i>
|
|
45
43
|
<div class="tooltip left">Change map projection</div>
|
|
46
44
|
</button>
|
|
@@ -49,23 +47,11 @@
|
|
|
49
47
|
class="primary small circle small-elevate"
|
|
50
48
|
@click="onCompareClick(compareIndicators)"
|
|
51
49
|
>
|
|
52
|
-
<i class="small"
|
|
53
|
-
|
|
50
|
+
<i class="small">
|
|
51
|
+
<svg viewBox="0 0 24 24"><path :d="compareIcon"></path></svg>
|
|
54
52
|
</i>
|
|
55
53
|
<div class="tooltip left">Compare mode</div>
|
|
56
54
|
</button>
|
|
57
|
-
<button
|
|
58
|
-
v-if="backToPOIs && (poi || comparePoi)"
|
|
59
|
-
class="primary small circle small-elevate"
|
|
60
|
-
@click="loadPOiIndicator()"
|
|
61
|
-
>
|
|
62
|
-
<i class="small"
|
|
63
|
-
><svg viewBox="0 0 24 24">
|
|
64
|
-
<path :d="mdiStarFourPointsCircleOutline" />
|
|
65
|
-
</svg>
|
|
66
|
-
</i>
|
|
67
|
-
<div class="tooltip left">Back to POIs</div>
|
|
68
|
-
</button>
|
|
69
55
|
<button
|
|
70
56
|
v-if="enableGlobe && !isInCompareMode"
|
|
71
57
|
class="primary small circle small-elevate"
|
|
@@ -102,20 +88,36 @@
|
|
|
102
88
|
@close="showFeedback = false"
|
|
103
89
|
></eox-feedback>
|
|
104
90
|
</div>
|
|
105
|
-
<
|
|
91
|
+
<button
|
|
106
92
|
v-if="mapEl && !isGlobe && enableSearch"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
93
|
+
class="primary small circle small-elevate"
|
|
94
|
+
>
|
|
95
|
+
<eox-geosearch
|
|
96
|
+
:for="mapEl"
|
|
97
|
+
:endpoint="opencageUrl"
|
|
98
|
+
:params="searchParams"
|
|
99
|
+
class="geosearch-detached"
|
|
100
|
+
label="Search"
|
|
101
|
+
small
|
|
102
|
+
button
|
|
103
|
+
list-direction="left"
|
|
104
|
+
results-direction="down"
|
|
105
|
+
tooltip="Search"
|
|
106
|
+
tooltip-direction="left"
|
|
107
|
+
></eox-geosearch>
|
|
108
|
+
</button>
|
|
109
|
+
<button
|
|
110
|
+
v-if="backToPOIs && (poi || comparePoi)"
|
|
111
|
+
class="primary small circle small-elevate"
|
|
112
|
+
@click="loadPOiIndicator()"
|
|
113
|
+
>
|
|
114
|
+
<i class="small">
|
|
115
|
+
<svg viewBox="0 0 24 24">
|
|
116
|
+
<path :d="mdiStarFourPointsCircleOutline"></path>
|
|
117
|
+
</svg>
|
|
118
|
+
</i>
|
|
119
|
+
<div class="tooltip left">Back to POIs</div>
|
|
120
|
+
</button>
|
|
119
121
|
<PopUp
|
|
120
122
|
v-model="showCompareIndicators"
|
|
121
123
|
:maxWidth="popupWidth"
|
|
@@ -126,9 +128,29 @@
|
|
|
126
128
|
<EodashItemFilter
|
|
127
129
|
v-bind="itemFilterConfig"
|
|
128
130
|
:enableCompare="true"
|
|
129
|
-
@select="onSelectCompareIndicator"
|
|
131
|
+
@select="onSelectCompareIndicator(compareIndicators)"
|
|
130
132
|
/>
|
|
131
133
|
</PopUp>
|
|
134
|
+
<v-alert
|
|
135
|
+
v-if="showMosaicHint"
|
|
136
|
+
class="mosaic-hint pa-2"
|
|
137
|
+
color="secondary"
|
|
138
|
+
type="info"
|
|
139
|
+
variant="elevated"
|
|
140
|
+
density="compact"
|
|
141
|
+
elevation="4"
|
|
142
|
+
>
|
|
143
|
+
<template v-if="showItemViewHint">
|
|
144
|
+
Viewing individual item —
|
|
145
|
+
<a class="mosaic-hint-link" @click.prevent="returnToOverview.emit()">
|
|
146
|
+
Back to overview
|
|
147
|
+
</a>
|
|
148
|
+
</template>
|
|
149
|
+
<template v-else-if="showZoomHint">Zoom in to explore the data</template>
|
|
150
|
+
<template v-else-if="showNoDataHint">
|
|
151
|
+
No data here - pan or change filters
|
|
152
|
+
</template>
|
|
153
|
+
</v-alert>
|
|
132
154
|
</div>
|
|
133
155
|
</template>
|
|
134
156
|
<script setup>
|
|
@@ -140,8 +162,10 @@ import {
|
|
|
140
162
|
comparePoi,
|
|
141
163
|
isGlobe,
|
|
142
164
|
mapEl,
|
|
165
|
+
mapPosition,
|
|
143
166
|
poi,
|
|
144
167
|
} from "@/store/states";
|
|
168
|
+
import { useMosaicState, normalizeGlobeZoom } from "@/eodashSTAC/mosaic";
|
|
145
169
|
import {
|
|
146
170
|
mdiCompare,
|
|
147
171
|
mdiCompareRemove,
|
|
@@ -195,11 +219,13 @@ const {
|
|
|
195
219
|
default: true,
|
|
196
220
|
},
|
|
197
221
|
compareIndicators: {
|
|
198
|
-
/**
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
222
|
+
/**
|
|
223
|
+
* @type {import("vue").PropType<boolean | {
|
|
224
|
+
* compareTemplate?:string;
|
|
225
|
+
* fallbackTemplate?:string;
|
|
226
|
+
* itemFilterConfig?:Partial<InstanceType<import("./EodashItemFilter.vue").default>["$props"]>
|
|
227
|
+
* }> }
|
|
228
|
+
*/
|
|
203
229
|
type: [Boolean, Object],
|
|
204
230
|
default: true,
|
|
205
231
|
},
|
|
@@ -267,6 +293,32 @@ useTransparentPanel(rootRef);
|
|
|
267
293
|
|
|
268
294
|
const opencageApiKey = process.env.EODASH_OPENCAGE || "NO_KEY_FOUND";
|
|
269
295
|
const opencageUrl = `https://api.opencagedata.com/geocode/v1/json?key=${opencageApiKey}`;
|
|
296
|
+
|
|
297
|
+
const {
|
|
298
|
+
latestLayer,
|
|
299
|
+
isItemView,
|
|
300
|
+
visibilityThreshold,
|
|
301
|
+
returnToOverview,
|
|
302
|
+
hasDataInView,
|
|
303
|
+
} = useMosaicState();
|
|
304
|
+
|
|
305
|
+
const showItemViewHint = computed(
|
|
306
|
+
() => isItemView.value && !!latestLayer.value,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const showZoomHint = computed(() => {
|
|
310
|
+
if (!latestLayer.value || isItemView.value) return false;
|
|
311
|
+
const rawZ = mapPosition.value?.[2] ?? 4;
|
|
312
|
+
return normalizeGlobeZoom(rawZ) < visibilityThreshold.value;
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const showNoDataHint = computed(
|
|
316
|
+
() => !!latestLayer.value && !isItemView.value && !hasDataInView.value,
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
const showMosaicHint = computed(
|
|
320
|
+
() => showItemViewHint.value || showZoomHint.value || showNoDataHint.value,
|
|
321
|
+
);
|
|
270
322
|
</script>
|
|
271
323
|
|
|
272
324
|
<style scoped>
|
|
@@ -296,11 +348,20 @@ const opencageUrl = `https://api.opencagedata.com/geocode/v1/json?key=${opencage
|
|
|
296
348
|
pointer-events: auto !important;
|
|
297
349
|
}
|
|
298
350
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
overflow: visible !important;
|
|
351
|
+
.mosaic-hint {
|
|
352
|
+
position: fixed;
|
|
353
|
+
left: 50%;
|
|
354
|
+
transform: translateX(-50%);
|
|
304
355
|
z-index: 10;
|
|
356
|
+
opacity: 0.8;
|
|
357
|
+
border-radius: 8px;
|
|
358
|
+
pointer-events: auto;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.mosaic-hint-link {
|
|
362
|
+
color: inherit;
|
|
363
|
+
cursor: pointer;
|
|
364
|
+
text-decoration: underline;
|
|
365
|
+
pointer-events: auto;
|
|
305
366
|
}
|
|
306
367
|
</style>
|