@eodash/eodash 5.7.0 → 5.7.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.
- 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 +74 -20
- package/core/client/eodashSTAC/cql.js +64 -0
- package/core/client/eodashSTAC/createLayers.js +169 -116
- package/core/client/eodashSTAC/helpers.js +391 -98
- package/core/client/eodashSTAC/mosaic.js +416 -0
- package/core/client/plugins/axios.js +31 -1
- package/core/client/store/actions.js +1 -1
- package/core/client/store/stac.js +25 -4
- package/core/client/store/states.js +20 -2
- package/core/client/types.ts +147 -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-ePbdvUTE.js} +2 -2
- package/dist/client/{DynamicWebComponent-CnKhYo0K.js → DynamicWebComponent-g5SdRbjY.js} +1 -1
- package/dist/client/{EodashChart-CLDqE93C.js → EodashChart-ChrkA5oS.js} +7 -6
- package/dist/client/{EodashDatePicker-CMPDT-ce.js → EodashDatePicker-CY1TrsDo.js} +3 -3
- package/dist/client/{EodashItemFilter-BpdA8QQa.js → EodashItemFilter-DzshHDlS.js} +2 -1
- package/dist/client/{EodashLayerControl-BHpDA4_0.js → EodashLayerControl-DMCeMkSd.js} +50 -20
- package/dist/client/{EodashLayoutSwitcher-B1fRUt7G.js → EodashLayoutSwitcher-iJ8mX1rF.js} +3 -3
- package/dist/client/{EodashMapBtns-Cpned0tc.js → EodashMapBtns-C7Cr7q5Y.js} +200 -86
- package/dist/client/EodashStacInfo-K7-iuXa7.js +169 -0
- package/dist/client/{EodashTools-1zHz26gv.js → EodashTools-BEK7e7JM.js} +4 -4
- package/dist/client/{ExportState-DbOm8hBI.js → ExportState-CqIzfMYQ.js} +6 -168
- package/dist/client/{Footer-BKg-VVkj.js → Footer-1P0cmBOZ.js} +1 -1
- package/dist/client/{Header-DCrwCvmY.js → Header-CkkBaBNh.js} +2 -2
- package/dist/client/{MobileLayout-vWSHpluo.js → MobileLayout-BPf49kDU.js} +2 -2
- package/dist/client/{PopUp-9uimfK49.js → PopUp-DPZq5SWI.js} +4 -168
- package/dist/client/{ProcessList-CTTIZa06.js → ProcessList-DuI6WpS1.js} +5 -5
- package/dist/client/VDivider-Bj9LG_JV.js +168 -0
- package/dist/client/{VImg-CrmB76ZY.js → VImg-Ddv5OyMz.js} +2 -2
- package/dist/client/{VMain-OKZNpcEG.js → VMain-7yqk_qC3.js} +1 -1
- package/dist/client/{VTooltip-CJw2FyWk.js → VTooltip-2hAJyEoa.js} +2 -2
- package/dist/client/{WidgetsContainer-BaWOnE5R.js → WidgetsContainer-2DOrlwCB.js} +1 -1
- package/dist/client/{asWebComponent-BHWpMuE3.js → asWebComponent-BlFN2lkB.js} +456 -306
- package/dist/client/{async-DSKj6g1f.js → async-B2H8ZwUK.js} +2 -2
- package/dist/client/{create-layers-config-CBoYedqB.js → create-layers-config-u_vn5hPk.js} +17 -17
- package/dist/client/dialog-transition-BrMkMiNa.js +170 -0
- package/dist/client/eo-dash.js +1 -1
- package/dist/client/{forwardRefs-DH51zPUr.js → forwardRefs-DAlror6d.js} +8 -87
- package/dist/client/{handling-BrcDDlgS.js → handling-B6I1V5eG.js} +3 -3
- package/dist/client/{helpers-DjZVl_WF.js → helpers-CBqIUSXJ.js} +794 -182
- package/dist/client/index-BWq1ZKaV.js +3168 -0
- package/dist/client/{index-CUjl-ZsI.js → index-CJ9UI3ln.js} +2 -2
- package/dist/client/{index-CSG_JoOA.js → index-DXLz4sFR.js} +62 -56
- package/dist/client/{index-1JKE68n3.js → index-DhKU6KqM.js} +211 -67
- package/dist/client/{index-Cu3-13Xg.js → index-DjQlbWbJ.js} +7 -6
- package/dist/client/mosaic-BFYLEwyx.js +455 -0
- package/dist/client/templates.js +250 -119
- package/dist/client/{transition-OHcz5Qq1.js → transition-D_W6Wn9v.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 +77 -18
- package/dist/types/core/client/eodashSTAC/mosaic.d.ts +56 -0
- package/dist/types/core/client/store/stac.d.ts +31 -7
- package/dist/types/core/client/store/states.d.ts +24 -2
- package/dist/types/core/client/types.d.ts +123 -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 +9 -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/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 +33 -33
- package/templates/baseConfig.js +36 -6
- package/templates/compare.js +62 -7
- package/templates/expert.js +23 -0
- package/templates/explore.js +11 -5
- package/templates/lite.js +14 -0
- package/widgets/EodashChart.vue +1 -0
- 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 +142 -28
- package/widgets/EodashLayerControl.vue +42 -11
- package/widgets/EodashMap/EodashMapBtns.vue +109 -48
- package/widgets/EodashMap/index.vue +89 -105
- package/widgets/EodashMap/methods/btns.js +37 -5
- 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 +52 -0
- package/widgets/EodashProcess/index.vue +1 -0
- 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/dist/client/EodashStacInfo-BQspAHKH.js +0 -107
- package/dist/client/index-5Jhsa8Xe.js +0 -570
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
compareIndicator,
|
|
81
81
|
poi,
|
|
82
82
|
isGlobe,
|
|
83
|
+
tooltipAdapter,
|
|
83
84
|
} from "@/store/states";
|
|
84
85
|
import { storeToRefs } from "pinia";
|
|
85
86
|
import { useSTAcStore } from "@/store/stac";
|
|
@@ -93,6 +94,7 @@ import {
|
|
|
93
94
|
import {
|
|
94
95
|
useHandleMapMoveEnd,
|
|
95
96
|
useInitMap,
|
|
97
|
+
useMapLoading,
|
|
96
98
|
useUpdateTooltipProperties,
|
|
97
99
|
} from "^/EodashMap/methods";
|
|
98
100
|
import { inAndOut } from "ol/easing.js";
|
|
@@ -100,42 +102,73 @@ import mustache from "mustache";
|
|
|
100
102
|
import EodashMapBtns from "^/EodashMap/EodashMapBtns.vue";
|
|
101
103
|
|
|
102
104
|
const props = defineProps({
|
|
105
|
+
baseLayers: {
|
|
106
|
+
/** @type {import("vue").PropType<import("@eox/map").EoxLayer[]>} */
|
|
107
|
+
type: Array,
|
|
108
|
+
default: () => [
|
|
109
|
+
{
|
|
110
|
+
type: "Tile",
|
|
111
|
+
source: { type: "OSM" },
|
|
112
|
+
properties: {
|
|
113
|
+
id: "osm",
|
|
114
|
+
title: "Background",
|
|
115
|
+
layerControlExclusive: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
},
|
|
103
120
|
enableCompare: {
|
|
104
121
|
type: Boolean,
|
|
105
122
|
default: false,
|
|
106
123
|
},
|
|
107
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Initial map center as [lon, lat]; falls back to the last stored map position.
|
|
126
|
+
* @default [15, 48]
|
|
127
|
+
*/
|
|
108
128
|
center: {
|
|
109
|
-
|
|
110
|
-
|
|
129
|
+
type: /** @type {import("vue").PropType<[number, number]>} */ (
|
|
130
|
+
/** @type {unknown} */ (Array)
|
|
131
|
+
),
|
|
111
132
|
default: () => [mapPosition.value?.[0] ?? 15, mapPosition.value?.[1] ?? 48],
|
|
112
133
|
},
|
|
134
|
+
/**
|
|
135
|
+
* Initial zoom level; falls back to the last stored map position.
|
|
136
|
+
* @default 4
|
|
137
|
+
*/
|
|
113
138
|
zoom: {
|
|
114
139
|
type: Number,
|
|
115
140
|
default: mapPosition.value?.[2] ?? 4,
|
|
116
141
|
},
|
|
142
|
+
/** Fly to the selected collection's spatial extent on selection. */
|
|
117
143
|
zoomToExtent: {
|
|
118
144
|
type: Boolean,
|
|
119
145
|
default: true,
|
|
120
146
|
},
|
|
147
|
+
/** Show live cursor coordinates as a fixed overlay at the bottom-left of the map. */
|
|
121
148
|
enableCursorCoordinates: {
|
|
122
149
|
type: Boolean,
|
|
123
150
|
default: true,
|
|
124
151
|
},
|
|
152
|
+
/** Show an OpenLayers scale-line control at the bottom-left of the map. */
|
|
125
153
|
enableScaleLine: {
|
|
126
154
|
type: Boolean,
|
|
127
155
|
default: true,
|
|
128
156
|
},
|
|
157
|
+
/** Grid position of the floating button toolbar. `x` accepts responsive `"mobile/tablet/desktop"` column notation. */
|
|
129
158
|
btnsPosition: {
|
|
130
|
-
type:
|
|
159
|
+
type: /** @type {import("vue").PropType<{ x: string | number; y: number; gap: number }>} */ (
|
|
160
|
+
Object
|
|
161
|
+
),
|
|
131
162
|
default: () => ({
|
|
132
163
|
x: "12/9/10",
|
|
133
164
|
y: 1,
|
|
134
165
|
gap: 16,
|
|
135
166
|
}),
|
|
136
167
|
},
|
|
168
|
+
/** Toolbar feature flags; set any flag to `false` to hide the corresponding button. */
|
|
137
169
|
btns: {
|
|
138
|
-
|
|
170
|
+
type: /**
|
|
171
|
+
* @type {import("vue").PropType<{
|
|
139
172
|
* enableExportMap?: boolean;
|
|
140
173
|
* enableChangeProjection?: boolean;
|
|
141
174
|
* enableBackToPOIs?: boolean;
|
|
@@ -143,14 +176,14 @@ const props = defineProps({
|
|
|
143
176
|
* searchParams?: object;
|
|
144
177
|
* enableZoom?: boolean;
|
|
145
178
|
* enableGlobe?: boolean;
|
|
179
|
+
* enableMosaic?: boolean;
|
|
146
180
|
* enableFeedback?: boolean;
|
|
147
181
|
* enableCompareIndicators?: boolean | {
|
|
148
182
|
* compareTemplate?:string;
|
|
149
183
|
* fallbackTemplate?:string;
|
|
150
184
|
* itemFilterConfig?:InstanceType<import("../EodashItemFilter.vue").default>["$props"]
|
|
151
185
|
* };
|
|
152
|
-
* }> }*/
|
|
153
|
-
type: Object,
|
|
186
|
+
* }> } */ (Object),
|
|
154
187
|
default: () => ({
|
|
155
188
|
enableExportMap: true,
|
|
156
189
|
enableChangeProjection: true,
|
|
@@ -159,6 +192,7 @@ const props = defineProps({
|
|
|
159
192
|
enableSearch: true,
|
|
160
193
|
enableZoom: true,
|
|
161
194
|
enableGlobe: true,
|
|
195
|
+
enableMosaic: true,
|
|
162
196
|
enableFeedback: true,
|
|
163
197
|
searchParams: {},
|
|
164
198
|
}),
|
|
@@ -203,6 +237,7 @@ const btnsProps = computed(() => ({
|
|
|
203
237
|
enableSearch: props.btns.enableSearch ?? true,
|
|
204
238
|
enableZoom: props.btns.enableZoom ?? true,
|
|
205
239
|
enableGlobe: props.btns.enableGlobe ?? true,
|
|
240
|
+
enableMosaic: props.btns.enableMosaic ?? true,
|
|
206
241
|
enableFeedback: props.btns.enableFeedback ?? true,
|
|
207
242
|
searchParams: props.btns.searchParams,
|
|
208
243
|
}));
|
|
@@ -218,22 +253,13 @@ const cursorCoordsRef = useTemplateRef("cursor-coords");
|
|
|
218
253
|
const tooltipProperties = ref([]);
|
|
219
254
|
/** @type {import("vue").Ref<Exclude<import("@/types").EodashStyleJson["tooltip"], undefined>>} */
|
|
220
255
|
const compareTooltipProperties = ref([]);
|
|
221
|
-
|
|
222
|
-
Attribution: { collapsible: boolean };
|
|
223
|
-
ScaleLine?: { target: HTMLElement };
|
|
224
|
-
MousePosition?: { projection: string; coordinateFormat: (c: [number, number]) => string; target: HTMLElement };
|
|
225
|
-
}>} */
|
|
256
|
+
|
|
226
257
|
const controls = computed(() => {
|
|
227
|
-
/** @type {{
|
|
228
|
-
Attribution: { collapsible: boolean };
|
|
229
|
-
ScaleLine?: { target: HTMLElement };
|
|
230
|
-
MousePosition?: { projection: string; coordinateFormat: (c: [number, number]) => string; target: HTMLElement };
|
|
231
|
-
}} */
|
|
232
|
-
const controlsObj = {
|
|
258
|
+
const controlsObj = /** @type {import("@eox/map").ControlDictionary} */ ({
|
|
233
259
|
Attribution: {
|
|
234
260
|
collapsible: true,
|
|
235
261
|
},
|
|
236
|
-
};
|
|
262
|
+
});
|
|
237
263
|
|
|
238
264
|
if (props.enableScaleLine && scaleLineRef.value) {
|
|
239
265
|
controlsObj.ScaleLine = {
|
|
@@ -244,12 +270,8 @@ const controls = computed(() => {
|
|
|
244
270
|
if (props.enableCursorCoordinates && cursorCoordsRef.value) {
|
|
245
271
|
controlsObj.MousePosition = {
|
|
246
272
|
projection: "EPSG:4326",
|
|
247
|
-
coordinateFormat: (
|
|
248
|
-
|
|
249
|
-
const lng = c[0];
|
|
250
|
-
const latStr = `${Math.abs(lat).toFixed(3)}°${lat >= 0 ? "N" : "S"}`;
|
|
251
|
-
const lngStr = `${Math.abs(lng).toFixed(3)}°${lng >= 0 ? "E" : "W"}`;
|
|
252
|
-
return `${latStr}, ${lngStr}`;
|
|
273
|
+
coordinateFormat: (c) => {
|
|
274
|
+
return `${c?.[1].toFixed(3)} °N, ${c?.[0].toFixed(3)} °E`;
|
|
253
275
|
},
|
|
254
276
|
target: cursorCoordsRef.value,
|
|
255
277
|
};
|
|
@@ -261,28 +283,17 @@ const controls = computed(() => {
|
|
|
261
283
|
const initialCenter = toRaw(props.center);
|
|
262
284
|
const initialZoom = toRaw(mapPosition.value?.[2] ?? props.zoom);
|
|
263
285
|
/** @type {import("vue").Ref<Record<string,any>[]>} */
|
|
264
|
-
const eoxMapLayers = ref(
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
id: "osm",
|
|
270
|
-
title: "Background",
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
]);
|
|
286
|
+
const eoxMapLayers = ref(
|
|
287
|
+
/** @type {Record<string,any>[]} */ (
|
|
288
|
+
structuredClone(toRaw(props.baseLayers))
|
|
289
|
+
),
|
|
290
|
+
);
|
|
274
291
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
properties: {
|
|
281
|
-
id: "osm",
|
|
282
|
-
title: "Background",
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
]);
|
|
292
|
+
const eoxMapCompareLayers = ref(
|
|
293
|
+
/** @type {Record<string,any>[]} */ (
|
|
294
|
+
structuredClone(toRaw(props.baseLayers))
|
|
295
|
+
),
|
|
296
|
+
);
|
|
286
297
|
|
|
287
298
|
const animationOptions = ref({
|
|
288
299
|
duration: 0, // Initially set to 0 for an instant "jump"
|
|
@@ -290,9 +301,10 @@ const animationOptions = ref({
|
|
|
290
301
|
});
|
|
291
302
|
|
|
292
303
|
/** @type {import("vue").Ref<import("@eox/map").EOxMap | null>} */
|
|
293
|
-
const eoxMap =
|
|
304
|
+
const eoxMap = useTemplateRef("eoxMap");
|
|
294
305
|
/** @type {import("vue").Ref<import("@eox/map").EOxMap | null>} */
|
|
295
|
-
const compareMap =
|
|
306
|
+
const compareMap = useTemplateRef("compareMap");
|
|
307
|
+
|
|
296
308
|
const { selectedCompareStac } = storeToRefs(useSTAcStore());
|
|
297
309
|
const showCompare = computed(() =>
|
|
298
310
|
props.enableCompare && !!selectedCompareStac.value ? "" : "first",
|
|
@@ -301,10 +313,20 @@ const showCompare = computed(() =>
|
|
|
301
313
|
useHandleMapMoveEnd(eoxMap, mapPosition);
|
|
302
314
|
|
|
303
315
|
onMounted(() => {
|
|
304
|
-
const {
|
|
305
|
-
|
|
316
|
+
const {
|
|
317
|
+
selectedCompareStac,
|
|
318
|
+
selectedStac,
|
|
319
|
+
selectedItem,
|
|
320
|
+
selectedCompareItem,
|
|
321
|
+
} = storeToRefs(useSTAcStore());
|
|
322
|
+
if (!eoxMap.value) {
|
|
323
|
+
console.error("EOxMap reference is not available on mounted.");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
306
326
|
// assign map Element state to eox map
|
|
307
327
|
mapEl.value = eoxMap.value;
|
|
328
|
+
// enable terrain
|
|
329
|
+
mapEl.value.globeConfig.terrain = true;
|
|
308
330
|
|
|
309
331
|
if (props.enableCompare) {
|
|
310
332
|
mapCompareEl.value = compareMap.value;
|
|
@@ -319,6 +341,8 @@ onMounted(() => {
|
|
|
319
341
|
eoxMapCompareLayers,
|
|
320
342
|
eoxMap,
|
|
321
343
|
false,
|
|
344
|
+
selectedCompareItem,
|
|
345
|
+
props.baseLayers,
|
|
322
346
|
);
|
|
323
347
|
|
|
324
348
|
useUpdateTooltipProperties(
|
|
@@ -337,6 +361,7 @@ onMounted(() => {
|
|
|
337
361
|
compareMap,
|
|
338
362
|
props.zoomToExtent,
|
|
339
363
|
selectedItem,
|
|
364
|
+
props.baseLayers,
|
|
340
365
|
);
|
|
341
366
|
// After the initial mount and "jump", set the animation duration for subsequent flyTo calls
|
|
342
367
|
nextTick(() => {
|
|
@@ -344,14 +369,23 @@ onMounted(() => {
|
|
|
344
369
|
});
|
|
345
370
|
});
|
|
346
371
|
|
|
372
|
+
// sync map loading with the global loading state
|
|
373
|
+
useMapLoading(eoxMap, compareMap);
|
|
374
|
+
|
|
347
375
|
useUpdateTooltipProperties(eodashCollections, tooltipProperties);
|
|
348
376
|
|
|
349
377
|
const mainTooltipStyles = computed(() => ({
|
|
350
|
-
visibility:
|
|
378
|
+
visibility:
|
|
379
|
+
tooltipProperties.value.length || !!tooltipAdapter.value
|
|
380
|
+
? "visible"
|
|
381
|
+
: "hidden",
|
|
351
382
|
}));
|
|
352
383
|
|
|
353
384
|
const compareTooltipStyles = computed(() => ({
|
|
354
|
-
visibility:
|
|
385
|
+
visibility:
|
|
386
|
+
compareTooltipProperties.value.length || !!tooltipAdapter.value
|
|
387
|
+
? "visible"
|
|
388
|
+
: "hidden",
|
|
355
389
|
}));
|
|
356
390
|
/**
|
|
357
391
|
* @param {"main" | "compare"} map
|
|
@@ -377,6 +411,9 @@ const tooltipPropertyTransform = (map) => {
|
|
|
377
411
|
(prop) => prop.id === param.key,
|
|
378
412
|
);
|
|
379
413
|
if (!tooltipProp) {
|
|
414
|
+
if (tooltipAdapter.value) {
|
|
415
|
+
return tooltipAdapter.value(param, map);
|
|
416
|
+
}
|
|
380
417
|
return undefined;
|
|
381
418
|
}
|
|
382
419
|
if (typeof param.value === "object") {
|
|
@@ -388,7 +425,6 @@ const tooltipPropertyTransform = (map) => {
|
|
|
388
425
|
: 4;
|
|
389
426
|
param.value = Number(param.value).toFixed(decimals).toString();
|
|
390
427
|
}
|
|
391
|
-
|
|
392
428
|
return {
|
|
393
429
|
key: tooltipProp.title || tooltipProp.id,
|
|
394
430
|
value: param.value + " " + (tooltipProp.appendix || ""),
|
|
@@ -405,58 +441,6 @@ onMounted(() => {
|
|
|
405
441
|
</script>
|
|
406
442
|
|
|
407
443
|
<style scoped>
|
|
408
|
-
#cursor-coordinates {
|
|
409
|
-
position: fixed;
|
|
410
|
-
left: 24px;
|
|
411
|
-
bottom: 54px; /* Tighter spacing: watermark at 6px + ~48px */
|
|
412
|
-
color: rgba(0, 0, 0, 0.9);
|
|
413
|
-
font-size: 10px;
|
|
414
|
-
font-family: var(--eox-body-font-family);
|
|
415
|
-
background: #fffe;
|
|
416
|
-
border-radius: 4px;
|
|
417
|
-
border: none;
|
|
418
|
-
padding: 0px 3px;
|
|
419
|
-
max-height: 24px;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
@media (max-width: 959px) {
|
|
423
|
-
#cursor-coordinates {
|
|
424
|
-
display: none; /* Hidden in mobile mode */
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
#scale-line {
|
|
429
|
-
position: fixed;
|
|
430
|
-
left: 24px;
|
|
431
|
-
bottom: 28px; /* Tighter spacing: watermark at 6px + ~22px */
|
|
432
|
-
color: #fff;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
@media (max-width: 959px) {
|
|
436
|
-
#scale-line {
|
|
437
|
-
bottom: 102px; /* Adjusted for mobile bottom nav - closer to coordinates */
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
:deep(.ol-scale-line) {
|
|
442
|
-
background: #fffe !important;
|
|
443
|
-
border-radius: 4px !important;
|
|
444
|
-
border: none !important;
|
|
445
|
-
padding: 0px 3px 3px 3px !important;
|
|
446
|
-
font-size: 10px !important;
|
|
447
|
-
font-family: var(--eox-body-font-family);
|
|
448
|
-
max-height: 20px;
|
|
449
|
-
}
|
|
450
|
-
:deep(.ol-scale-line-inner) {
|
|
451
|
-
display: flex;
|
|
452
|
-
justify-content: center;
|
|
453
|
-
border: 1px solid rgba(0, 0, 0, 0.5) !important;
|
|
454
|
-
border-top: none !important;
|
|
455
|
-
color: #333 !important;
|
|
456
|
-
font-weight: 500 !important;
|
|
457
|
-
transform: translateY(1px);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
444
|
.map-buttons-container {
|
|
461
445
|
position: fixed;
|
|
462
446
|
left: 0;
|
|
@@ -11,7 +11,20 @@ export const switchGlobe = () => {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
if (!isGlobe.value) {
|
|
14
|
-
|
|
14
|
+
// tmp: we remove the vector layers from the globe until
|
|
15
|
+
// we have better support for them
|
|
16
|
+
const layers = addCorsAnonym([...getLayers()])
|
|
17
|
+
.filter((layer) => layer.type !== "Vector")
|
|
18
|
+
.map((layer) => {
|
|
19
|
+
if (layer.type === "Group") {
|
|
20
|
+
return {
|
|
21
|
+
...layer,
|
|
22
|
+
layers: layer.layers.filter((l) => l.type !== "Vector"),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return layer;
|
|
26
|
+
});
|
|
27
|
+
mapEl.value.layers = layers;
|
|
15
28
|
}
|
|
16
29
|
mapEl.value.projection = isGlobe.value ? "EPSG:3857" : "globe";
|
|
17
30
|
if (isGlobe.value) {
|
|
@@ -20,27 +33,46 @@ export const switchGlobe = () => {
|
|
|
20
33
|
isGlobe.value = !isGlobe.value;
|
|
21
34
|
};
|
|
22
35
|
|
|
36
|
+
function getRoot() {
|
|
37
|
+
const eodashComponent = document.querySelector("eo-dash");
|
|
38
|
+
return eodashComponent ? eodashComponent.shadowRoot : document;
|
|
39
|
+
}
|
|
40
|
+
|
|
23
41
|
function hideAllPanels() {
|
|
24
|
-
const
|
|
42
|
+
const root = getRoot();
|
|
43
|
+
const allPanels = root?.querySelectorAll(
|
|
25
44
|
"eox-layout-item:not([class='bg-panel'])",
|
|
26
45
|
);
|
|
27
|
-
|
|
46
|
+
|
|
47
|
+
allPanels?.forEach((panel) => {
|
|
28
48
|
if (!panel || !(panel instanceof HTMLElement)) {
|
|
29
49
|
return;
|
|
30
50
|
}
|
|
31
51
|
panel.style.display = "none";
|
|
32
52
|
});
|
|
53
|
+
|
|
54
|
+
const mapButtons = root?.querySelector(".map-buttons");
|
|
55
|
+
if (mapButtons instanceof HTMLElement) {
|
|
56
|
+
mapButtons.style.padding = "1rem";
|
|
57
|
+
}
|
|
33
58
|
}
|
|
59
|
+
|
|
34
60
|
function showAllPanels() {
|
|
35
|
-
const
|
|
61
|
+
const root = getRoot();
|
|
62
|
+
const allPanels = root?.querySelectorAll(
|
|
36
63
|
"eox-layout-item:not([class='bg-panel'])",
|
|
37
64
|
);
|
|
38
|
-
allPanels
|
|
65
|
+
allPanels?.forEach((panel) => {
|
|
39
66
|
if (!panel || !(panel instanceof HTMLElement)) {
|
|
40
67
|
return;
|
|
41
68
|
}
|
|
42
69
|
panel.style.display = "";
|
|
43
70
|
});
|
|
71
|
+
|
|
72
|
+
const mapButtons = root?.querySelector(".map-buttons");
|
|
73
|
+
if (mapButtons instanceof HTMLElement) {
|
|
74
|
+
mapButtons.style.padding = "";
|
|
75
|
+
}
|
|
44
76
|
}
|
|
45
77
|
/**
|
|
46
78
|
*
|
|
@@ -10,6 +10,7 @@ import log from "loglevel";
|
|
|
10
10
|
* } selectedIndicator
|
|
11
11
|
* @param {EodashCollection[]} eodashCols
|
|
12
12
|
* @param {string | import("stac-ts").StacItem | null} [timeOrItem] - time as a string, or a stac item
|
|
13
|
+
* @param {Record<string, any>[]} [defaultBaseLayers] - Optional default baselayers to use if the indicator does not provide any
|
|
13
14
|
* @returns {Promise<Record<string, any>[]>}
|
|
14
15
|
*/
|
|
15
16
|
|
|
@@ -17,6 +18,7 @@ export const createLayersConfig = async (
|
|
|
17
18
|
selectedIndicator,
|
|
18
19
|
eodashCols,
|
|
19
20
|
timeOrItem,
|
|
21
|
+
defaultBaseLayers = [],
|
|
20
22
|
) => {
|
|
21
23
|
log.debug(
|
|
22
24
|
"Creating layers config",
|
|
@@ -38,17 +40,25 @@ export const createLayersConfig = async (
|
|
|
38
40
|
for (const ec of eodashCols) {
|
|
39
41
|
/** @type {Record<string,any>[]} */
|
|
40
42
|
let layers;
|
|
43
|
+
let dateOrItem;
|
|
41
44
|
if (timeOrItem) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
if (typeof timeOrItem === "string" && timeOrItem.includes("/")) {
|
|
46
|
+
dateOrItem = timeOrItem;
|
|
47
|
+
} else {
|
|
48
|
+
dateOrItem =
|
|
49
|
+
typeof timeOrItem === "string" ? new Date(timeOrItem) : timeOrItem;
|
|
50
|
+
}
|
|
51
|
+
layers = await ec.createLayersJson(/** @type {any} */ (dateOrItem));
|
|
45
52
|
} else {
|
|
46
53
|
layers = await ec.createLayersJson(undefined);
|
|
47
54
|
}
|
|
55
|
+
|
|
48
56
|
// Add expand to all analysis layers
|
|
49
57
|
layers.forEach((dl) => {
|
|
50
|
-
dl.properties
|
|
51
|
-
|
|
58
|
+
if (!dl.properties?.layerControlExclusive) {
|
|
59
|
+
dl.properties.layerControlExpand = true;
|
|
60
|
+
dl.properties.layerControlToolsExpand = true;
|
|
61
|
+
}
|
|
52
62
|
});
|
|
53
63
|
dataLayers.layers.push(...layers);
|
|
54
64
|
}
|
|
@@ -141,17 +151,7 @@ export const createLayersConfig = async (
|
|
|
141
151
|
});
|
|
142
152
|
} else {
|
|
143
153
|
// Default to some baselayer
|
|
144
|
-
baseLayers.layers.push(
|
|
145
|
-
type: "Tile",
|
|
146
|
-
properties: {
|
|
147
|
-
id: "osm",
|
|
148
|
-
title: "Background",
|
|
149
|
-
layerControlExclusive: true,
|
|
150
|
-
},
|
|
151
|
-
source: {
|
|
152
|
-
type: "OSM",
|
|
153
|
-
},
|
|
154
|
-
});
|
|
154
|
+
baseLayers.layers.push(...defaultBaseLayers);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if (baseLayers.layers.length) {
|
|
@@ -6,9 +6,12 @@ import { useSTAcStore } from "@/store/stac";
|
|
|
6
6
|
import { storeToRefs } from "pinia";
|
|
7
7
|
import { isFirstLoad } from "@/utils/states";
|
|
8
8
|
import { useEmitLayersUpdate, useOnLayersUpdate } from "@/composables";
|
|
9
|
-
|
|
9
|
+
export { useEmitLayersUpdate, useOnLayersUpdate };
|
|
10
|
+
import { isGlobe, mapPosition } from "@/store/states";
|
|
10
11
|
import { sanitizeBbox } from "@/eodashSTAC/helpers";
|
|
11
12
|
import { transformExtent } from "@eox/map";
|
|
13
|
+
|
|
14
|
+
export { useMapLoading } from "./use-map-loading";
|
|
12
15
|
/**
|
|
13
16
|
* Holder for previous compare map view as it is overwritten by sync
|
|
14
17
|
* @type { import("ol").View | null} mapElement
|
|
@@ -39,14 +42,52 @@ export const useHandleMapMoveEnd = (mapElement, mapPosition) => {
|
|
|
39
42
|
}
|
|
40
43
|
};
|
|
41
44
|
|
|
45
|
+
const handleGlobeMoveEnd = () => {
|
|
46
|
+
const camera = mapElement.value?.globe?.planet?.camera;
|
|
47
|
+
const lonLat = camera?.getLonLat();
|
|
48
|
+
if (!lonLat) return;
|
|
49
|
+
const { lon, lat, height } = lonLat;
|
|
50
|
+
if (![lon, lat, height].some(Number.isNaN)) {
|
|
51
|
+
mapPosition.value = [lon, lat, height];
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** @type {{ events: { off: Function } } | null} */
|
|
56
|
+
let subscribedCamera = null;
|
|
57
|
+
|
|
58
|
+
const subscribeGlobe = (retries = 3) => {
|
|
59
|
+
if (!isGlobe.value) return; // toggled back out during retry
|
|
60
|
+
const camera = mapElement.value?.globe?.planet?.camera;
|
|
61
|
+
if (camera) {
|
|
62
|
+
if (subscribedCamera === camera) return;
|
|
63
|
+
camera.events.on("moveend", handleGlobeMoveEnd);
|
|
64
|
+
subscribedCamera = camera;
|
|
65
|
+
handleGlobeMoveEnd();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (retries > 0) setTimeout(() => subscribeGlobe(retries - 1), 50);
|
|
69
|
+
};
|
|
70
|
+
const unsubscribeGlobe = () => {
|
|
71
|
+
subscribedCamera?.events.off("moveend", handleGlobeMoveEnd);
|
|
72
|
+
subscribedCamera = null;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const stopGlobeWatch = watch(isGlobe, (globe) =>
|
|
76
|
+
globe ? subscribeGlobe() : unsubscribeGlobe(),
|
|
77
|
+
);
|
|
78
|
+
|
|
42
79
|
onMounted(() => {
|
|
43
|
-
|
|
44
|
-
|
|
80
|
+
const map = mapElement.value?.map;
|
|
81
|
+
map?.on("moveend", handleMoveEnd);
|
|
82
|
+
// Seed mapPosition from the initial view
|
|
83
|
+
handleMoveEnd(/** @type {any} */ ({ map }));
|
|
45
84
|
});
|
|
46
85
|
|
|
47
86
|
onUnmounted(() => {
|
|
48
87
|
/** @type {import('ol/Map').default} */
|
|
49
88
|
(mapElement.value?.map)?.un("moveend", handleMoveEnd);
|
|
89
|
+
unsubscribeGlobe();
|
|
90
|
+
stopGlobeWatch();
|
|
50
91
|
});
|
|
51
92
|
};
|
|
52
93
|
|
|
@@ -61,6 +102,7 @@ export const useHandleMapMoveEnd = (mapElement, mapPosition) => {
|
|
|
61
102
|
* @param {import("vue").Ref<import("@eox/map").EOxMap| null>} partnerMap
|
|
62
103
|
* @param {boolean} zoomToExtent
|
|
63
104
|
* @param {import("vue").Ref<import("stac-ts").StacItem | import("stac-ts").StacLink | null>} [selectedItem]
|
|
105
|
+
* @param {Record<string, any>[]} [defaultBaseLayers]
|
|
64
106
|
*/
|
|
65
107
|
export const useInitMap = (
|
|
66
108
|
mapElement,
|
|
@@ -71,6 +113,7 @@ export const useInitMap = (
|
|
|
71
113
|
partnerMap,
|
|
72
114
|
zoomToExtent,
|
|
73
115
|
selectedItem,
|
|
116
|
+
defaultBaseLayers,
|
|
74
117
|
) => {
|
|
75
118
|
log.debug(
|
|
76
119
|
"InitMap",
|
|
@@ -100,12 +143,24 @@ export const useInitMap = (
|
|
|
100
143
|
);
|
|
101
144
|
|
|
102
145
|
if (updatedStac) {
|
|
103
|
-
|
|
146
|
+
const isSameStac = updatedStac?.id === previousStac?.id;
|
|
147
|
+
const isSameItem = updatedItem?.id === previousItem?.id;
|
|
148
|
+
|
|
149
|
+
// Item deselect: overview render is owned by the item catalog widget.
|
|
150
|
+
const isItemDeselect =
|
|
151
|
+
previousItem &&
|
|
152
|
+
!updatedItem &&
|
|
153
|
+
isSameStac &&
|
|
154
|
+
updatedTime === previousTime;
|
|
155
|
+
if (isItemDeselect) return;
|
|
156
|
+
|
|
157
|
+
// Re-fire from our own datetime.value write, skip and clear
|
|
158
|
+
const isOwnDatetimeUpdate =
|
|
104
159
|
internalDatetime !== null &&
|
|
105
160
|
updatedTime === internalDatetime &&
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
) {
|
|
161
|
+
isSameStac &&
|
|
162
|
+
isSameItem;
|
|
163
|
+
if (isOwnDatetimeUpdate) {
|
|
109
164
|
internalDatetime = null;
|
|
110
165
|
return;
|
|
111
166
|
}
|
|
@@ -153,7 +208,9 @@ export const useInitMap = (
|
|
|
153
208
|
updatedStac,
|
|
154
209
|
eodashCols,
|
|
155
210
|
updatedItem ?? updatedTime,
|
|
211
|
+
defaultBaseLayers,
|
|
156
212
|
);
|
|
213
|
+
|
|
157
214
|
log.debug(
|
|
158
215
|
"Assigned layers after changing time only",
|
|
159
216
|
JSON.parse(JSON.stringify(layersCollection)),
|
|
@@ -175,6 +232,11 @@ export const useInitMap = (
|
|
|
175
232
|
if (interval && interval.length > 0 && interval[0].length > 1) {
|
|
176
233
|
// @ts-expect-error this is the defined STAC structure
|
|
177
234
|
endInterval = new Date(interval[0][1]);
|
|
235
|
+
// If end interval is in the future, set to now,
|
|
236
|
+
// for item fetching based on search endpoint
|
|
237
|
+
if (endInterval.getTime() > Date.now()) {
|
|
238
|
+
endInterval = new Date();
|
|
239
|
+
}
|
|
178
240
|
log.debug(
|
|
179
241
|
"Indicator load: found stac extent, setting time to latest value",
|
|
180
242
|
endInterval,
|
|
@@ -200,7 +262,8 @@ export const useInitMap = (
|
|
|
200
262
|
layersCollection = await createLayersConfig(
|
|
201
263
|
updatedStac,
|
|
202
264
|
eodashCols,
|
|
203
|
-
resolvedTime,
|
|
265
|
+
updatedItem ?? resolvedTime,
|
|
266
|
+
defaultBaseLayers,
|
|
204
267
|
);
|
|
205
268
|
|
|
206
269
|
if (zoomToExtent) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { onUnmounted, watch } from "vue";
|
|
2
|
+
import { loading } from "@/store/states";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tracks map loading state at the source level via `loading.activeLoads`,
|
|
6
|
+
* the same counter used by the axios plugin. Re-attaches source listeners
|
|
7
|
+
* whenever eox-map fires `layerschanged`, using `getFlatLayersArray`.
|
|
8
|
+
*
|
|
9
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} mapElement
|
|
10
|
+
* @param {import("vue").Ref<import("@eox/map").EOxMap | null>} compareMapElement
|
|
11
|
+
*/
|
|
12
|
+
export const useMapLoading = (mapElement, compareMapElement) => {
|
|
13
|
+
const startHandler = () => {
|
|
14
|
+
loading.activeLoads++;
|
|
15
|
+
};
|
|
16
|
+
const endHandler = () => {
|
|
17
|
+
loading.activeLoads--;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** @param {import("@eox/map").EOxMap | null} newMapEl */
|
|
21
|
+
const watcherHandler = (newMapEl) => {
|
|
22
|
+
if (!newMapEl) return;
|
|
23
|
+
|
|
24
|
+
const hasStartListener = newMapEl.map
|
|
25
|
+
.getListeners("loadstart")
|
|
26
|
+
?.some((listner) => listner === startHandler);
|
|
27
|
+
const hasEndListener = newMapEl.map
|
|
28
|
+
.getListeners("loadend")
|
|
29
|
+
?.some((listner) => listner === endHandler);
|
|
30
|
+
|
|
31
|
+
if (!hasStartListener) {
|
|
32
|
+
newMapEl.map.addEventListener("loadstart", startHandler);
|
|
33
|
+
}
|
|
34
|
+
if (!hasEndListener) {
|
|
35
|
+
newMapEl.map.addEventListener("loadend", endHandler);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const stopMainWatcher = watch(mapElement, watcherHandler, {
|
|
39
|
+
immediate: true,
|
|
40
|
+
});
|
|
41
|
+
const stopCompareWatcher = watch(compareMapElement, watcherHandler, {
|
|
42
|
+
immediate: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
onUnmounted(() => {
|
|
46
|
+
mapElement.value?.map.removeEventListener("loadstart", startHandler);
|
|
47
|
+
mapElement.value?.map.removeEventListener("loadend", endHandler);
|
|
48
|
+
stopMainWatcher();
|
|
49
|
+
stopCompareWatcher();
|
|
50
|
+
loading.activeLoads = 0;
|
|
51
|
+
});
|
|
52
|
+
};
|