@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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { toAbsolute } from 'stac-js/src/http.js';
|
|
2
2
|
import { setupCache } from 'axios-cache-interceptor';
|
|
3
3
|
import log from 'loglevel';
|
|
4
|
-
import { ref, shallowRef } from 'vue';
|
|
4
|
+
import { ref, shallowRef, reactive, shallowReactive } from 'vue';
|
|
5
|
+
import { mdiWrench, mdiSnowflake, mdiVolleyball, mdiHiking, mdiLightningBolt, mdiLeaf, mdiAccountMultiple, mdiCurrencyEur, mdiWeatherWindy, mdiSetCenter, mdiHospitalBoxOutline, mdiImageFilterHdr, mdiWater, mdiBarley } from '@mdi/js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Create a bound version of a function with a specified `this` context
|
|
@@ -426,7 +427,9 @@ function merge(...objs) {
|
|
|
426
427
|
return;
|
|
427
428
|
}
|
|
428
429
|
|
|
429
|
-
|
|
430
|
+
// findKey lowercases the key, so caseless lookup only applies to strings —
|
|
431
|
+
// symbol keys are identity-matched.
|
|
432
|
+
const targetKey = (caseless && typeof key === 'string' && findKey(result, key)) || key;
|
|
430
433
|
// Read via own-prop only — a bare `result[targetKey]` walks the prototype
|
|
431
434
|
// chain, so a polluted Object.prototype value could surface here and get
|
|
432
435
|
// copied into the merged result.
|
|
@@ -443,7 +446,24 @@ function merge(...objs) {
|
|
|
443
446
|
};
|
|
444
447
|
|
|
445
448
|
for (let i = 0, l = objs.length; i < l; i++) {
|
|
446
|
-
|
|
449
|
+
const source = objs[i];
|
|
450
|
+
if (!source || isBuffer(source)) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
forEach(source, assignValue);
|
|
455
|
+
|
|
456
|
+
if (typeof source !== 'object' || isArray(source)) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const symbols = Object.getOwnPropertySymbols(source);
|
|
461
|
+
for (let j = 0; j < symbols.length; j++) {
|
|
462
|
+
const symbol = symbols[j];
|
|
463
|
+
if (propertyIsEnumerable.call(source, symbol)) {
|
|
464
|
+
assignValue(source[symbol], symbol);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
447
467
|
}
|
|
448
468
|
return result;
|
|
449
469
|
}
|
|
@@ -672,6 +692,8 @@ const hasOwnProperty = (
|
|
|
672
692
|
hasOwnProperty.call(obj, prop)
|
|
673
693
|
)(Object.prototype);
|
|
674
694
|
|
|
695
|
+
const { propertyIsEnumerable } = Object.prototype;
|
|
696
|
+
|
|
675
697
|
/**
|
|
676
698
|
* Determine if a value is a RegExp object
|
|
677
699
|
*
|
|
@@ -777,11 +799,11 @@ function isSpecCompliantForm(thing) {
|
|
|
777
799
|
* @returns {Object} The JSON-compatible object.
|
|
778
800
|
*/
|
|
779
801
|
const toJSONObject = (obj) => {
|
|
780
|
-
const
|
|
802
|
+
const visited = new WeakSet();
|
|
781
803
|
|
|
782
|
-
const visit = (source
|
|
804
|
+
const visit = (source) => {
|
|
783
805
|
if (isObject(source)) {
|
|
784
|
-
if (
|
|
806
|
+
if (visited.has(source)) {
|
|
785
807
|
return;
|
|
786
808
|
}
|
|
787
809
|
|
|
@@ -791,15 +813,16 @@ const toJSONObject = (obj) => {
|
|
|
791
813
|
}
|
|
792
814
|
|
|
793
815
|
if (!('toJSON' in source)) {
|
|
794
|
-
|
|
816
|
+
// add-on descent / delete-on-ascent: preserves path semantics, so DAG nodes serialise at every occurrence (see #7230).
|
|
817
|
+
visited.add(source);
|
|
795
818
|
const target = isArray(source) ? [] : {};
|
|
796
819
|
|
|
797
820
|
forEach(source, (value, key) => {
|
|
798
|
-
const reducedValue = visit(value
|
|
821
|
+
const reducedValue = visit(value);
|
|
799
822
|
!isUndefined(reducedValue) && (target[key] = reducedValue);
|
|
800
823
|
});
|
|
801
824
|
|
|
802
|
-
|
|
825
|
+
visited.delete(source);
|
|
803
826
|
|
|
804
827
|
return target;
|
|
805
828
|
}
|
|
@@ -808,7 +831,7 @@ const toJSONObject = (obj) => {
|
|
|
808
831
|
return source;
|
|
809
832
|
};
|
|
810
833
|
|
|
811
|
-
return visit(obj
|
|
834
|
+
return visit(obj);
|
|
812
835
|
};
|
|
813
836
|
|
|
814
837
|
/**
|
|
@@ -1010,10 +1033,6 @@ const parseHeaders = (rawHeaders) => {
|
|
|
1010
1033
|
return parsed;
|
|
1011
1034
|
};
|
|
1012
1035
|
|
|
1013
|
-
const $internals = Symbol('internals');
|
|
1014
|
-
|
|
1015
|
-
const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
|
|
1016
|
-
|
|
1017
1036
|
function trimSPorHTAB(str) {
|
|
1018
1037
|
let start = 0;
|
|
1019
1038
|
let end = str.length;
|
|
@@ -1041,12 +1060,40 @@ function trimSPorHTAB(str) {
|
|
|
1041
1060
|
return start === 0 && end === str.length ? str : str.slice(start, end);
|
|
1042
1061
|
}
|
|
1043
1062
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1063
|
+
// The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
|
|
1064
|
+
// eslint-disable-next-line no-control-regex
|
|
1065
|
+
const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp('[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+', 'g');
|
|
1066
|
+
// eslint-disable-next-line no-control-regex
|
|
1067
|
+
const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp('[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+', 'g');
|
|
1068
|
+
|
|
1069
|
+
function sanitizeValue(value, invalidChars) {
|
|
1070
|
+
if (utils$1.isArray(value)) {
|
|
1071
|
+
return value.map((item) => sanitizeValue(item, invalidChars));
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
return trimSPorHTAB(String(value).replace(invalidChars, ''));
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const sanitizeHeaderValue = (value) =>
|
|
1078
|
+
sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
|
|
1079
|
+
|
|
1080
|
+
const sanitizeByteStringHeaderValue = (value) =>
|
|
1081
|
+
sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
|
|
1082
|
+
|
|
1083
|
+
function toByteStringHeaderObject(headers) {
|
|
1084
|
+
const byteStringHeaders = Object.create(null);
|
|
1085
|
+
|
|
1086
|
+
utils$1.forEach(headers.toJSON(), (value, header) => {
|
|
1087
|
+
byteStringHeaders[header] = sanitizeByteStringHeaderValue(value);
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
return byteStringHeaders;
|
|
1046
1091
|
}
|
|
1047
1092
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1093
|
+
const $internals = Symbol('internals');
|
|
1094
|
+
|
|
1095
|
+
function normalizeHeader(header) {
|
|
1096
|
+
return header && String(header).trim().toLowerCase();
|
|
1050
1097
|
}
|
|
1051
1098
|
|
|
1052
1099
|
function normalizeValue(value) {
|
|
@@ -1128,7 +1175,7 @@ class AxiosHeaders {
|
|
|
1128
1175
|
const lHeader = normalizeHeader(_header);
|
|
1129
1176
|
|
|
1130
1177
|
if (!lHeader) {
|
|
1131
|
-
|
|
1178
|
+
return;
|
|
1132
1179
|
}
|
|
1133
1180
|
|
|
1134
1181
|
const key = utils$1.findKey(self, lHeader);
|
|
@@ -1156,7 +1203,7 @@ class AxiosHeaders {
|
|
|
1156
1203
|
key;
|
|
1157
1204
|
for (const entry of header) {
|
|
1158
1205
|
if (!utils$1.isArray(entry)) {
|
|
1159
|
-
throw TypeError('Object iterator must return a key-value pair');
|
|
1206
|
+
throw new TypeError('Object iterator must return a key-value pair');
|
|
1160
1207
|
}
|
|
1161
1208
|
|
|
1162
1209
|
obj[(key = entry[0])] = (dest = obj[key])
|
|
@@ -1771,7 +1818,7 @@ function toFormData(obj, formData, options) {
|
|
|
1771
1818
|
}
|
|
1772
1819
|
|
|
1773
1820
|
if (stack.indexOf(value) !== -1) {
|
|
1774
|
-
throw Error('Circular reference detected in ' + path.join('.'));
|
|
1821
|
+
throw new Error('Circular reference detected in ' + path.join('.'));
|
|
1775
1822
|
}
|
|
1776
1823
|
|
|
1777
1824
|
stack.push(value);
|
|
@@ -1988,6 +2035,7 @@ const transitionalDefaults = {
|
|
|
1988
2035
|
forcedJSONParsing: true,
|
|
1989
2036
|
clarifyTimeoutError: false,
|
|
1990
2037
|
legacyInterceptorReqResOrdering: true,
|
|
2038
|
+
advertiseZstdAcceptEncoding: false,
|
|
1991
2039
|
};
|
|
1992
2040
|
|
|
1993
2041
|
const URLSearchParams$1 = typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams;
|
|
@@ -2145,7 +2193,7 @@ function formDataToJSON(formData) {
|
|
|
2145
2193
|
return !isNumericKey;
|
|
2146
2194
|
}
|
|
2147
2195
|
|
|
2148
|
-
if (!target
|
|
2196
|
+
if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
|
|
2149
2197
|
target[name] = [];
|
|
2150
2198
|
}
|
|
2151
2199
|
|
|
@@ -2510,6 +2558,9 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
|
|
2510
2558
|
const _speedometer = speedometer(50, 250);
|
|
2511
2559
|
|
|
2512
2560
|
return throttle((e) => {
|
|
2561
|
+
if (!e || typeof e.loaded !== 'number') {
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2513
2564
|
const rawLoaded = e.loaded;
|
|
2514
2565
|
const total = e.lengthComputable ? e.total : undefined;
|
|
2515
2566
|
const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
|
|
@@ -2819,12 +2870,12 @@ function setFormDataHeaders(headers, formHeaders, policy) {
|
|
|
2819
2870
|
*
|
|
2820
2871
|
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
2821
2872
|
*/
|
|
2822
|
-
const encodeUTF8 = (str) =>
|
|
2873
|
+
const encodeUTF8$1 = (str) =>
|
|
2823
2874
|
encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
|
|
2824
2875
|
String.fromCharCode(parseInt(hex, 16))
|
|
2825
2876
|
);
|
|
2826
2877
|
|
|
2827
|
-
|
|
2878
|
+
function resolveConfig(config) {
|
|
2828
2879
|
const newConfig = mergeConfig({}, config);
|
|
2829
2880
|
|
|
2830
2881
|
// Read only own properties to prevent prototype pollution gadgets
|
|
@@ -2845,8 +2896,8 @@ const resolveConfig = (config) => {
|
|
|
2845
2896
|
|
|
2846
2897
|
newConfig.url = buildURL(
|
|
2847
2898
|
buildFullPath(baseURL, url, allowAbsoluteUrls),
|
|
2848
|
-
|
|
2849
|
-
|
|
2899
|
+
own('params'),
|
|
2900
|
+
own('paramsSerializer')
|
|
2850
2901
|
);
|
|
2851
2902
|
|
|
2852
2903
|
// HTTP basic authentication
|
|
@@ -2854,13 +2905,17 @@ const resolveConfig = (config) => {
|
|
|
2854
2905
|
headers.set(
|
|
2855
2906
|
'Authorization',
|
|
2856
2907
|
'Basic ' +
|
|
2857
|
-
btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : ''))
|
|
2908
|
+
btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8$1(auth.password) : ''))
|
|
2858
2909
|
);
|
|
2859
2910
|
}
|
|
2860
2911
|
|
|
2861
2912
|
if (utils$1.isFormData(data)) {
|
|
2862
|
-
if (
|
|
2863
|
-
|
|
2913
|
+
if (
|
|
2914
|
+
platform.hasStandardBrowserEnv ||
|
|
2915
|
+
platform.hasStandardBrowserWebWorkerEnv ||
|
|
2916
|
+
utils$1.isReactNative(data)
|
|
2917
|
+
) {
|
|
2918
|
+
headers.setContentType(undefined); // browser/web worker/RN handles it
|
|
2864
2919
|
} else if (utils$1.isFunction(data.getHeaders)) {
|
|
2865
2920
|
// Node.js FormData (like form-data package)
|
|
2866
2921
|
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
|
|
@@ -2892,7 +2947,7 @@ const resolveConfig = (config) => {
|
|
|
2892
2947
|
}
|
|
2893
2948
|
|
|
2894
2949
|
return newConfig;
|
|
2895
|
-
}
|
|
2950
|
+
}
|
|
2896
2951
|
|
|
2897
2952
|
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
|
|
2898
2953
|
|
|
@@ -3041,7 +3096,7 @@ const xhrAdapter = isXHRAdapterSupported &&
|
|
|
3041
3096
|
|
|
3042
3097
|
// Add headers to the request
|
|
3043
3098
|
if ('setRequestHeader' in request) {
|
|
3044
|
-
utils$1.forEach(requestHeaders
|
|
3099
|
+
utils$1.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) {
|
|
3045
3100
|
request.setRequestHeader(key, val);
|
|
3046
3101
|
});
|
|
3047
3102
|
}
|
|
@@ -3111,54 +3166,55 @@ const xhrAdapter = isXHRAdapterSupported &&
|
|
|
3111
3166
|
};
|
|
3112
3167
|
|
|
3113
3168
|
const composeSignals = (signals, timeout) => {
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
if (timeout || length) {
|
|
3117
|
-
let controller = new AbortController();
|
|
3118
|
-
|
|
3119
|
-
let aborted;
|
|
3120
|
-
|
|
3121
|
-
const onabort = function (reason) {
|
|
3122
|
-
if (!aborted) {
|
|
3123
|
-
aborted = true;
|
|
3124
|
-
unsubscribe();
|
|
3125
|
-
const err = reason instanceof Error ? reason : this.reason;
|
|
3126
|
-
controller.abort(
|
|
3127
|
-
err instanceof AxiosError
|
|
3128
|
-
? err
|
|
3129
|
-
: new CanceledError(err instanceof Error ? err.message : err)
|
|
3130
|
-
);
|
|
3131
|
-
}
|
|
3132
|
-
};
|
|
3169
|
+
signals = signals ? signals.filter(Boolean) : [];
|
|
3133
3170
|
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
timer = null;
|
|
3138
|
-
onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
|
|
3139
|
-
}, timeout);
|
|
3140
|
-
|
|
3141
|
-
const unsubscribe = () => {
|
|
3142
|
-
if (signals) {
|
|
3143
|
-
timer && clearTimeout(timer);
|
|
3144
|
-
timer = null;
|
|
3145
|
-
signals.forEach((signal) => {
|
|
3146
|
-
signal.unsubscribe
|
|
3147
|
-
? signal.unsubscribe(onabort)
|
|
3148
|
-
: signal.removeEventListener('abort', onabort);
|
|
3149
|
-
});
|
|
3150
|
-
signals = null;
|
|
3151
|
-
}
|
|
3152
|
-
};
|
|
3171
|
+
if (!timeout && !signals.length) {
|
|
3172
|
+
return;
|
|
3173
|
+
}
|
|
3153
3174
|
|
|
3154
|
-
|
|
3175
|
+
const controller = new AbortController();
|
|
3155
3176
|
|
|
3156
|
-
|
|
3177
|
+
let aborted = false;
|
|
3157
3178
|
|
|
3158
|
-
|
|
3179
|
+
const onabort = function (reason) {
|
|
3180
|
+
if (!aborted) {
|
|
3181
|
+
aborted = true;
|
|
3182
|
+
unsubscribe();
|
|
3183
|
+
const err = reason instanceof Error ? reason : this.reason;
|
|
3184
|
+
controller.abort(
|
|
3185
|
+
err instanceof AxiosError
|
|
3186
|
+
? err
|
|
3187
|
+
: new CanceledError(err instanceof Error ? err.message : err)
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
3190
|
+
};
|
|
3159
3191
|
|
|
3160
|
-
|
|
3161
|
-
|
|
3192
|
+
let timer =
|
|
3193
|
+
timeout &&
|
|
3194
|
+
setTimeout(() => {
|
|
3195
|
+
timer = null;
|
|
3196
|
+
onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
|
|
3197
|
+
}, timeout);
|
|
3198
|
+
|
|
3199
|
+
const unsubscribe = () => {
|
|
3200
|
+
if (!signals) { return; }
|
|
3201
|
+
timer && clearTimeout(timer);
|
|
3202
|
+
timer = null;
|
|
3203
|
+
signals.forEach((signal) => {
|
|
3204
|
+
signal.unsubscribe
|
|
3205
|
+
? signal.unsubscribe(onabort)
|
|
3206
|
+
: signal.removeEventListener('abort', onabort);
|
|
3207
|
+
});
|
|
3208
|
+
signals = null;
|
|
3209
|
+
};
|
|
3210
|
+
|
|
3211
|
+
signals.forEach((signal) => signal.addEventListener('abort', onabort));
|
|
3212
|
+
|
|
3213
|
+
const { signal } = controller;
|
|
3214
|
+
|
|
3215
|
+
signal.unsubscribe = () => utils$1.asap(unsubscribe);
|
|
3216
|
+
|
|
3217
|
+
return signal;
|
|
3162
3218
|
};
|
|
3163
3219
|
|
|
3164
3220
|
const streamChunk = function* (chunk, chunkSize) {
|
|
@@ -3352,12 +3408,41 @@ function estimateDataURLDecodedBytes(url) {
|
|
|
3352
3408
|
return bytes;
|
|
3353
3409
|
}
|
|
3354
3410
|
|
|
3355
|
-
const VERSION = "1.
|
|
3411
|
+
const VERSION = "1.17.0";
|
|
3356
3412
|
|
|
3357
3413
|
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
3358
3414
|
|
|
3359
3415
|
const { isFunction } = utils$1;
|
|
3360
3416
|
|
|
3417
|
+
/**
|
|
3418
|
+
* Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
|
|
3419
|
+
* This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
|
|
3420
|
+
*
|
|
3421
|
+
* @param {string} str The string to encode
|
|
3422
|
+
*
|
|
3423
|
+
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
3424
|
+
*/
|
|
3425
|
+
const encodeUTF8 = (str) =>
|
|
3426
|
+
encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
|
|
3427
|
+
String.fromCharCode(parseInt(hex, 16))
|
|
3428
|
+
);
|
|
3429
|
+
|
|
3430
|
+
// Node's WHATWG URL parser returns `username` and `password` percent-encoded.
|
|
3431
|
+
// Decode before composing the `auth` option so credentials such as
|
|
3432
|
+
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
3433
|
+
// original value for malformed input so a bad encoding never throws.
|
|
3434
|
+
const decodeURIComponentSafe = (value) => {
|
|
3435
|
+
if (!utils$1.isString(value)) {
|
|
3436
|
+
return value;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
try {
|
|
3440
|
+
return decodeURIComponent(value);
|
|
3441
|
+
} catch (error) {
|
|
3442
|
+
return value;
|
|
3443
|
+
}
|
|
3444
|
+
};
|
|
3445
|
+
|
|
3361
3446
|
const test = (fn, ...args) => {
|
|
3362
3447
|
try {
|
|
3363
3448
|
return !!fn(...args);
|
|
@@ -3366,8 +3451,20 @@ const test = (fn, ...args) => {
|
|
|
3366
3451
|
}
|
|
3367
3452
|
};
|
|
3368
3453
|
|
|
3454
|
+
const maybeWithAuthCredentials = (url) => {
|
|
3455
|
+
const protocolIndex = url.indexOf('://');
|
|
3456
|
+
let urlToCheck = url;
|
|
3457
|
+
if (protocolIndex !== -1) {
|
|
3458
|
+
urlToCheck = urlToCheck.slice(protocolIndex + 3);
|
|
3459
|
+
}
|
|
3460
|
+
return urlToCheck.includes('@') || urlToCheck.includes(':');
|
|
3461
|
+
};
|
|
3462
|
+
|
|
3369
3463
|
const factory = (env) => {
|
|
3370
|
-
const globalObject =
|
|
3464
|
+
const globalObject =
|
|
3465
|
+
utils$1.global !== undefined && utils$1.global !== null
|
|
3466
|
+
? utils$1.global
|
|
3467
|
+
: globalThis;
|
|
3371
3468
|
const { ReadableStream, TextEncoder } = globalObject;
|
|
3372
3469
|
|
|
3373
3470
|
env = utils$1.merge.call(
|
|
@@ -3510,6 +3607,7 @@ const factory = (env) => {
|
|
|
3510
3607
|
|
|
3511
3608
|
const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
|
|
3512
3609
|
const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
|
|
3610
|
+
const own = (key) => (utils$1.hasOwnProp(config, key) ? config[key] : undefined);
|
|
3513
3611
|
|
|
3514
3612
|
let _fetch = envFetch || fetch;
|
|
3515
3613
|
|
|
@@ -3532,6 +3630,46 @@ const factory = (env) => {
|
|
|
3532
3630
|
let requestContentLength;
|
|
3533
3631
|
|
|
3534
3632
|
try {
|
|
3633
|
+
// HTTP basic authentication
|
|
3634
|
+
let auth = undefined;
|
|
3635
|
+
const configAuth = own('auth');
|
|
3636
|
+
|
|
3637
|
+
if (configAuth) {
|
|
3638
|
+
const username = configAuth.username || '';
|
|
3639
|
+
const password = configAuth.password || '';
|
|
3640
|
+
auth = {
|
|
3641
|
+
username,
|
|
3642
|
+
password
|
|
3643
|
+
};
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
if (maybeWithAuthCredentials(url)) {
|
|
3647
|
+
const parsedURL = new URL(url, platform.origin);
|
|
3648
|
+
|
|
3649
|
+
if (!auth && (parsedURL.username || parsedURL.password)) {
|
|
3650
|
+
const urlUsername = decodeURIComponentSafe(parsedURL.username);
|
|
3651
|
+
const urlPassword = decodeURIComponentSafe(parsedURL.password);
|
|
3652
|
+
auth = {
|
|
3653
|
+
username: urlUsername,
|
|
3654
|
+
password: urlPassword
|
|
3655
|
+
};
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3658
|
+
if (parsedURL.username || parsedURL.password) {
|
|
3659
|
+
parsedURL.username = '';
|
|
3660
|
+
parsedURL.password = '';
|
|
3661
|
+
url = parsedURL.href;
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
if (auth) {
|
|
3666
|
+
headers.delete('authorization');
|
|
3667
|
+
headers.set(
|
|
3668
|
+
'Authorization',
|
|
3669
|
+
'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || '')))
|
|
3670
|
+
);
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3535
3673
|
// Enforce maxContentLength for data: URLs up-front so we never materialize
|
|
3536
3674
|
// an oversized payload. The HTTP adapter applies the same check (see http.js
|
|
3537
3675
|
// "if (protocol === 'data:')" branch).
|
|
@@ -3624,7 +3762,7 @@ const factory = (env) => {
|
|
|
3624
3762
|
...fetchOptions,
|
|
3625
3763
|
signal: composedSignal,
|
|
3626
3764
|
method: method.toUpperCase(),
|
|
3627
|
-
headers: headers.normalize()
|
|
3765
|
+
headers: toByteStringHeaderObject(headers.normalize()),
|
|
3628
3766
|
body: data,
|
|
3629
3767
|
duplex: 'half',
|
|
3630
3768
|
credentials: isCredentialsSupported ? withCredentials : undefined,
|
|
@@ -4213,6 +4351,7 @@ class Axios {
|
|
|
4213
4351
|
forcedJSONParsing: validators.transitional(validators.boolean),
|
|
4214
4352
|
clarifyTimeoutError: validators.transitional(validators.boolean),
|
|
4215
4353
|
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
|
|
4354
|
+
advertiseZstdAcceptEncoding: validators.transitional(validators.boolean),
|
|
4216
4355
|
},
|
|
4217
4356
|
false
|
|
4218
4357
|
);
|
|
@@ -4699,10 +4838,6 @@ axios$1.HttpStatusCode = HttpStatusCode;
|
|
|
4699
4838
|
|
|
4700
4839
|
axios$1.default = axios$1;
|
|
4701
4840
|
|
|
4702
|
-
const instance = axios$1.create();
|
|
4703
|
-
|
|
4704
|
-
const axios = setupCache(instance, { cacheTakeover: false });
|
|
4705
|
-
|
|
4706
4841
|
/** setting default log level globally to warning */
|
|
4707
4842
|
log.setLevel(log.levels.WARN, true);
|
|
4708
4843
|
|
|
@@ -4732,7 +4867,7 @@ const registeredProjections = ["EPSG:4326", "EPSG:3857"];
|
|
|
4732
4867
|
/** available projection to be rendered by `EodashMap` */
|
|
4733
4868
|
const availableMapProjection = ref("EPSG:3857");
|
|
4734
4869
|
|
|
4735
|
-
/** @type {import("vue").Ref<import("@eox/map").EOxMap | null>} */
|
|
4870
|
+
/** @type {import("vue").Ref<import("@eox/map").EOxMap & { mapUpdateId?: number } | null>} */
|
|
4736
4871
|
const mapEl = shallowRef(null);
|
|
4737
4872
|
|
|
4738
4873
|
/** @type {import("vue").Ref<import("@eox/map").EOxMap | null>} */
|
|
@@ -4776,6 +4911,24 @@ const chartSpec = ref(null);
|
|
|
4776
4911
|
*/
|
|
4777
4912
|
const compareChartSpec = ref(null);
|
|
4778
4913
|
|
|
4914
|
+
/**
|
|
4915
|
+
* Global loading state.
|
|
4916
|
+
* - `loading.activeLoads` — increment/decrement to track concurrent loads
|
|
4917
|
+
* - `loading.value` — derived boolean, true when `activeLoads > 0`
|
|
4918
|
+
*/
|
|
4919
|
+
const loading = reactive({
|
|
4920
|
+
activeLoads: 0,
|
|
4921
|
+
get value() {
|
|
4922
|
+
return this.activeLoads > 0;
|
|
4923
|
+
},
|
|
4924
|
+
});
|
|
4925
|
+
|
|
4926
|
+
/**
|
|
4927
|
+
* Adapter allows external widgets to hook into tooltip property transformation
|
|
4928
|
+
* @type {import("vue").Ref<((param: {key: string, value: any}, map?: string) => {key: string, value: any} | undefined) | null>}
|
|
4929
|
+
*/
|
|
4930
|
+
const tooltipAdapter = shallowRef(null);
|
|
4931
|
+
|
|
4779
4932
|
const states = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
4780
4933
|
__proto__: null,
|
|
4781
4934
|
activeTemplate,
|
|
@@ -4792,13 +4945,180 @@ const states = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
|
4792
4945
|
datetime,
|
|
4793
4946
|
indicator,
|
|
4794
4947
|
isGlobe,
|
|
4948
|
+
loading,
|
|
4795
4949
|
mapCompareEl,
|
|
4796
4950
|
mapEl,
|
|
4797
4951
|
mapPosition,
|
|
4798
4952
|
poi,
|
|
4799
|
-
registeredProjections
|
|
4953
|
+
registeredProjections,
|
|
4954
|
+
tooltipAdapter
|
|
4800
4955
|
}, Symbol.toStringTag, { value: 'Module' }));
|
|
4801
4956
|
|
|
4957
|
+
const instance = axios$1.create();
|
|
4958
|
+
const axios = setupCache(instance, { cacheTakeover: false });
|
|
4959
|
+
function installLoadingInterceptors() {
|
|
4960
|
+
const reqId = axios.interceptors.request.use((config) => {
|
|
4961
|
+
loading.activeLoads++;
|
|
4962
|
+
return config;
|
|
4963
|
+
});
|
|
4964
|
+
const resId = axios.interceptors.response.use(
|
|
4965
|
+
(response) => {
|
|
4966
|
+
loading.activeLoads = Math.max(0, loading.activeLoads - 1);
|
|
4967
|
+
return response;
|
|
4968
|
+
},
|
|
4969
|
+
(error) => {
|
|
4970
|
+
loading.activeLoads = Math.max(0, loading.activeLoads - 1);
|
|
4971
|
+
return Promise.reject(error);
|
|
4972
|
+
}
|
|
4973
|
+
);
|
|
4974
|
+
return () => {
|
|
4975
|
+
axios.interceptors.request.eject(reqId);
|
|
4976
|
+
axios.interceptors.response.eject(resId);
|
|
4977
|
+
};
|
|
4978
|
+
}
|
|
4979
|
+
installLoadingInterceptors();
|
|
4980
|
+
|
|
4981
|
+
/**
|
|
4982
|
+
* Array of eodash STAC Collections extracted from the current selected indicator.
|
|
4983
|
+
* Updated in {@link file://./../store/stac.js `loadSelectedSTAC`} widget
|
|
4984
|
+
*
|
|
4985
|
+
* @type {import('../eodashSTAC/EodashCollection').EodashCollection[]}
|
|
4986
|
+
* @private
|
|
4987
|
+
*/
|
|
4988
|
+
const eodashCollections = shallowReactive([]);
|
|
4989
|
+
|
|
4990
|
+
/**
|
|
4991
|
+
* Array of eodash STAC Collections extracted from the current selected COMPARE indicator.
|
|
4992
|
+
* Updated in {@link file://./../store/stac.js ` loadSelectedCompareSTAC`} widget
|
|
4993
|
+
*
|
|
4994
|
+
* @type {import('../eodashSTAC/EodashCollection').EodashCollection[]}
|
|
4995
|
+
* @private
|
|
4996
|
+
*/
|
|
4997
|
+
const eodashCompareCollections = shallowReactive([]);
|
|
4998
|
+
|
|
4999
|
+
/** whether it's the first load of the app, used to track if there are params in the url */
|
|
5000
|
+
const isFirstLoad = ref(false);
|
|
5001
|
+
|
|
5002
|
+
/**
|
|
5003
|
+
* Current value of the layer control JSON form for the latest layer the user interacted with.
|
|
5004
|
+
* @type {import("vue").Ref<Record<string, any> | undefined>}
|
|
5005
|
+
*/
|
|
5006
|
+
const layerControlFormValue = ref({});
|
|
5007
|
+
|
|
5008
|
+
/**
|
|
5009
|
+
* Current value of the layer control JSON form for the latest layer the user interacted with.
|
|
5010
|
+
* @type {import("vue").Ref<Record<string, any> | undefined>}
|
|
5011
|
+
*/
|
|
5012
|
+
const layerControlFormValueCompare = ref({});
|
|
5013
|
+
|
|
5014
|
+
/**
|
|
5015
|
+
* STAC indicators color palette, defaults to Bank-Wong palette
|
|
5016
|
+
* @type {string[]} */
|
|
5017
|
+
const collectionsPalette = reactive([
|
|
5018
|
+
"#009E73",
|
|
5019
|
+
"#0072B2",
|
|
5020
|
+
"#E69F00",
|
|
5021
|
+
"#CC79A7",
|
|
5022
|
+
"#56B4E9",
|
|
5023
|
+
"#D55E00",
|
|
5024
|
+
]);
|
|
5025
|
+
|
|
5026
|
+
/**
|
|
5027
|
+
* Object containing data themes and their associated brand properties (icon and color).
|
|
5028
|
+
*/
|
|
5029
|
+
const dataThemesBrands = {
|
|
5030
|
+
agriculture: {
|
|
5031
|
+
icon: mdiBarley,
|
|
5032
|
+
color: "#F2AF25",
|
|
5033
|
+
},
|
|
5034
|
+
water: {
|
|
5035
|
+
icon: mdiWater,
|
|
5036
|
+
color: "#73A6C7",
|
|
5037
|
+
},
|
|
5038
|
+
oceans: {
|
|
5039
|
+
icon: mdiWater,
|
|
5040
|
+
color: "#6DA2C5",
|
|
5041
|
+
},
|
|
5042
|
+
land: {
|
|
5043
|
+
icon: mdiImageFilterHdr,
|
|
5044
|
+
color: "#019E73",
|
|
5045
|
+
},
|
|
5046
|
+
health: {
|
|
5047
|
+
icon: mdiHospitalBoxOutline,
|
|
5048
|
+
color: "#32322C",
|
|
5049
|
+
},
|
|
5050
|
+
"covid-19": {
|
|
5051
|
+
icon: mdiHospitalBoxOutline,
|
|
5052
|
+
color: "#32322C",
|
|
5053
|
+
},
|
|
5054
|
+
combined: {
|
|
5055
|
+
icon: mdiSetCenter,
|
|
5056
|
+
color: "#56B4E9",
|
|
5057
|
+
},
|
|
5058
|
+
air: {
|
|
5059
|
+
icon: mdiWeatherWindy,
|
|
5060
|
+
color: "#475faf",
|
|
5061
|
+
},
|
|
5062
|
+
atmosphere: {
|
|
5063
|
+
icon: mdiWeatherWindy,
|
|
5064
|
+
color: "#475faf",
|
|
5065
|
+
},
|
|
5066
|
+
climate: {
|
|
5067
|
+
icon: mdiWeatherWindy,
|
|
5068
|
+
color: "#475faf",
|
|
5069
|
+
},
|
|
5070
|
+
economy: {
|
|
5071
|
+
icon: mdiCurrencyEur,
|
|
5072
|
+
color: "#8E81AF",
|
|
5073
|
+
},
|
|
5074
|
+
commerce: {
|
|
5075
|
+
icon: mdiCurrencyEur,
|
|
5076
|
+
color: "#8E81AF",
|
|
5077
|
+
},
|
|
5078
|
+
society: {
|
|
5079
|
+
icon: mdiAccountMultiple,
|
|
5080
|
+
color: "#8ac501",
|
|
5081
|
+
},
|
|
5082
|
+
biomass: {
|
|
5083
|
+
icon: mdiLeaf,
|
|
5084
|
+
color: "#009E73",
|
|
5085
|
+
},
|
|
5086
|
+
extremes: {
|
|
5087
|
+
icon: mdiLightningBolt,
|
|
5088
|
+
color: "#a1280a",
|
|
5089
|
+
},
|
|
5090
|
+
energy: {
|
|
5091
|
+
icon: mdiLightningBolt,
|
|
5092
|
+
color: "#475faf",
|
|
5093
|
+
},
|
|
5094
|
+
tourism: {
|
|
5095
|
+
icon: mdiHiking,
|
|
5096
|
+
color: "#80510aff",
|
|
5097
|
+
},
|
|
5098
|
+
sport: {
|
|
5099
|
+
icon: mdiVolleyball,
|
|
5100
|
+
color: "#e98e65ff",
|
|
5101
|
+
},
|
|
5102
|
+
cryosphere: {
|
|
5103
|
+
icon: mdiSnowflake,
|
|
5104
|
+
color: "#42C7B8",
|
|
5105
|
+
},
|
|
5106
|
+
industry: {
|
|
5107
|
+
icon: mdiWrench,
|
|
5108
|
+
color: "#8d845cff",
|
|
5109
|
+
},
|
|
5110
|
+
};
|
|
5111
|
+
|
|
5112
|
+
/** @type {Map<string, import("stac-ts").StacItem[]>} */
|
|
5113
|
+
const itemsCache = new Map();
|
|
5114
|
+
/**
|
|
5115
|
+
* Split items cache stores items with their time range metadata
|
|
5116
|
+
* @type {Map<string, {items: import("stac-ts").StacItem[], minTime: number, maxTime: number}>}
|
|
5117
|
+
*/
|
|
5118
|
+
const splitItemsCache = new Map();
|
|
5119
|
+
|
|
5120
|
+
ref(0);
|
|
5121
|
+
|
|
4802
5122
|
/**
|
|
4803
5123
|
* Returns the current layers of {@link mapEl}
|
|
4804
5124
|
* @returns {import("@eox/map").EoxLayer[]}
|
|
@@ -4807,7 +5127,7 @@ const getLayers = () => mapEl.value?.layers ?? [];
|
|
|
4807
5127
|
|
|
4808
5128
|
/**
|
|
4809
5129
|
* Returns the current layers of {@link mapCompareEl}
|
|
4810
|
-
*
|
|
5130
|
+
* @returns {import("@eox/map").EoxLayer[]}
|
|
4811
5131
|
*/
|
|
4812
5132
|
const getCompareLayers = () => mapCompareEl.value?.layers ?? [];
|
|
4813
5133
|
|
|
@@ -5173,7 +5493,7 @@ const extractRoles = (properties, linkOrAsset) => {
|
|
|
5173
5493
|
|
|
5174
5494
|
/**
|
|
5175
5495
|
* Extracts a single non-link style JSON from a STAC Item optionally for a selected key mapping
|
|
5176
|
-
* @param { import("stac-ts").StacItem | import("stac-ts").StacCollection } stacObject
|
|
5496
|
+
* @param { import("stac-ts").StacItem | import("stac-ts").StacCollection | null | undefined} stacObject
|
|
5177
5497
|
* @param {string | undefined} linkKey
|
|
5178
5498
|
* @param {string | undefined} assetKey
|
|
5179
5499
|
* @returns
|
|
@@ -5183,6 +5503,7 @@ const fetchStyle = async (
|
|
|
5183
5503
|
linkKey = undefined,
|
|
5184
5504
|
assetKey = undefined,
|
|
5185
5505
|
) => {
|
|
5506
|
+
if (!stacObject) return undefined;
|
|
5186
5507
|
let styleLink = null;
|
|
5187
5508
|
if (linkKey) {
|
|
5188
5509
|
styleLink = stacObject.links.find(
|
|
@@ -5214,6 +5535,20 @@ const fetchStyle = async (
|
|
|
5214
5535
|
}
|
|
5215
5536
|
};
|
|
5216
5537
|
|
|
5538
|
+
/**
|
|
5539
|
+
* Resolves a style by preferring the item's own `style` link and falling back
|
|
5540
|
+
* to the collection's. Takes the same key arguments as `fetchStyle`.
|
|
5541
|
+
*
|
|
5542
|
+
* @param {import("stac-ts").StacItem | import("stac-ts").StacCollection} item
|
|
5543
|
+
* @param {import("stac-ts").StacCollection | null | undefined} collection
|
|
5544
|
+
* @param {string} [linkKey]
|
|
5545
|
+
* @param {string} [assetKey]
|
|
5546
|
+
* @returns {Promise<import("@/types").EodashStyleJson | undefined>}
|
|
5547
|
+
*/
|
|
5548
|
+
const resolveStyle = async (item, collection, linkKey, assetKey) =>
|
|
5549
|
+
(await fetchStyle(item, linkKey, assetKey)) ??
|
|
5550
|
+
(await fetchStyle(collection, linkKey, assetKey));
|
|
5551
|
+
|
|
5217
5552
|
/**
|
|
5218
5553
|
* Fetches all style JSONs from a STAC Item and returns an array with style objects
|
|
5219
5554
|
* @param {import("stac-ts").StacItem | import("stac-ts").StacCollection} stacObject
|
|
@@ -5253,94 +5588,74 @@ const getProjectionCode = (projection) => {
|
|
|
5253
5588
|
};
|
|
5254
5589
|
|
|
5255
5590
|
/**
|
|
5256
|
-
*
|
|
5257
|
-
*
|
|
5258
|
-
* @param {
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
// check if items has a datetime value
|
|
5266
|
-
const dateProperty = getDatetimeProperty(items);
|
|
5267
|
-
|
|
5268
|
-
if (!dateProperty) {
|
|
5591
|
+
* Builds layercontrol LayerDatetime + timeControlValues from a list of dates.
|
|
5592
|
+
*
|
|
5593
|
+
* @param {Date[] | undefined} dates
|
|
5594
|
+
* @param {string | null} [currentStep] - target datetime; snapped to the closest available date
|
|
5595
|
+
* @returns {{ layerDatetime: Record<string, any> | undefined, timeControlValues: { date: string }[] | undefined }}
|
|
5596
|
+
*/
|
|
5597
|
+
const extractLayerTimeValues = (dates, currentStep) => {
|
|
5598
|
+
if (!currentStep || !dates?.length || dates.length <= 1) {
|
|
5269
5599
|
return { layerDatetime: undefined, timeControlValues: undefined };
|
|
5270
5600
|
}
|
|
5271
|
-
/** @type {{date:string;itemId:string}[]} */
|
|
5272
|
-
const timeValues = [];
|
|
5273
|
-
try {
|
|
5274
|
-
/**
|
|
5275
|
-
* @param {typeof timeValues} vals
|
|
5276
|
-
* @param {import("stac-ts").StacLink} link
|
|
5277
|
-
*/
|
|
5278
|
-
const reduceLinks = (vals, link) => {
|
|
5279
|
-
if (link[dateProperty] && link.rel === "item") {
|
|
5280
|
-
vals.push({
|
|
5281
|
-
itemId: /** @type {string} */ (link.id),
|
|
5282
|
-
date: new Date(
|
|
5283
|
-
/** @type {string} */ (link[dateProperty]),
|
|
5284
|
-
).toISOString(),
|
|
5285
|
-
});
|
|
5286
|
-
}
|
|
5287
|
-
return vals;
|
|
5288
|
-
};
|
|
5289
5601
|
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
* @param {typeof timeValues} vals
|
|
5293
|
-
* @param {import("stac-ts").StacItem} item
|
|
5294
|
-
*/
|
|
5295
|
-
const reduceItems = (vals, item) => {
|
|
5296
|
-
const date = item.properties?.[dateProperty];
|
|
5297
|
-
if (date) {
|
|
5298
|
-
vals.push({
|
|
5299
|
-
itemId: /** @type {string} */ (item.id),
|
|
5300
|
-
date: new Date(/** @type {string} */ (date)).toISOString(),
|
|
5301
|
-
...item.properties,
|
|
5302
|
-
});
|
|
5303
|
-
}
|
|
5304
|
-
return vals;
|
|
5305
|
-
};
|
|
5306
|
-
currentStep = new Date(currentStep).toISOString();
|
|
5307
|
-
//@ts-expect-error TODO
|
|
5308
|
-
items.reduce(isSTACItem(items[0]) ? reduceItems : reduceLinks, timeValues);
|
|
5309
|
-
} catch (e) {
|
|
5310
|
-
console.warn("[eodash] not supported datetime format was provided", e);
|
|
5311
|
-
return { layerDatetime: undefined, timeControlValues: undefined };
|
|
5312
|
-
}
|
|
5313
|
-
// not enough timeValues
|
|
5314
|
-
if (timeValues.length <= 1) {
|
|
5315
|
-
return { layerDatetime: undefined, timeControlValues: undefined };
|
|
5316
|
-
}
|
|
5602
|
+
const controlValues = dates.map((d) => d.toISOString()).sort();
|
|
5603
|
+
const timeControlValues = controlValues.map((date) => ({ date }));
|
|
5317
5604
|
|
|
5318
|
-
|
|
5319
|
-
if (!
|
|
5320
|
-
const
|
|
5321
|
-
currentStep =
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5605
|
+
currentStep = new Date(currentStep).toISOString();
|
|
5606
|
+
if (!controlValues.includes(currentStep)) {
|
|
5607
|
+
const target = new Date(currentStep).getTime();
|
|
5608
|
+
currentStep = controlValues.reduce((best, d) =>
|
|
5609
|
+
Math.abs(new Date(d).getTime() - target) <
|
|
5610
|
+
Math.abs(new Date(best).getTime() - target)
|
|
5611
|
+
? d
|
|
5612
|
+
: best,
|
|
5613
|
+
);
|
|
5326
5614
|
}
|
|
5327
5615
|
|
|
5328
5616
|
const layerDatetime = {
|
|
5329
|
-
controlValues
|
|
5617
|
+
controlValues,
|
|
5330
5618
|
currentStep,
|
|
5331
5619
|
slider: true,
|
|
5332
5620
|
navigation: true,
|
|
5333
5621
|
play: false,
|
|
5334
5622
|
displayFormat: "DD.MM.YYYY HH:mm",
|
|
5335
5623
|
animateOnClickInterval: false,
|
|
5624
|
+
showUTC: true,
|
|
5336
5625
|
};
|
|
5337
5626
|
|
|
5338
|
-
return {
|
|
5339
|
-
layerDatetime,
|
|
5340
|
-
timeControlValues: timeValues,
|
|
5341
|
-
};
|
|
5627
|
+
return { layerDatetime, timeControlValues };
|
|
5342
5628
|
};
|
|
5343
5629
|
|
|
5630
|
+
/**
|
|
5631
|
+
* Fetches the daily pre-aggregation data for a STAC collection if available.
|
|
5632
|
+
* Returns the raw AggregationCollection,
|
|
5633
|
+
* or null if no daily pre-aggregation link exists, or the fetch fails.
|
|
5634
|
+
*
|
|
5635
|
+
* @param {import("stac-ts").StacCollection | undefined} stacCollection
|
|
5636
|
+
* @param {string} fallbackBaseUrl - base for relative href resolution when no `self` link is present
|
|
5637
|
+
* @returns {Promise<any | null>}
|
|
5638
|
+
*/
|
|
5639
|
+
async function fetchPreAggregations(stacCollection, fallbackBaseUrl) {
|
|
5640
|
+
if (!stacCollection) return null;
|
|
5641
|
+
const preAggregationLink = stacCollection.links?.find(
|
|
5642
|
+
(l) => l.rel === "pre-aggregation" && l["aggregation:interval"] === "daily",
|
|
5643
|
+
);
|
|
5644
|
+
if (!preAggregationLink) return null;
|
|
5645
|
+
|
|
5646
|
+
try {
|
|
5647
|
+
const selfLink = stacCollection.links?.find((l) => l.rel === "self")?.href;
|
|
5648
|
+
const url = toAbsolute(
|
|
5649
|
+
preAggregationLink.href,
|
|
5650
|
+
selfLink || fallbackBaseUrl,
|
|
5651
|
+
);
|
|
5652
|
+
return await axios.get(url).then((resp) => resp.data);
|
|
5653
|
+
} catch (e) {
|
|
5654
|
+
console.warn("[eodash] Failed to fetch pre-aggregation", e);
|
|
5655
|
+
return null;
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5658
|
+
|
|
5344
5659
|
/**
|
|
5345
5660
|
* Recursively find all layers whose ID up to the first ; is same as given layer
|
|
5346
5661
|
*
|
|
@@ -5349,6 +5664,9 @@ const extractLayerTimeValues = (items, currentStep) => {
|
|
|
5349
5664
|
* @returns {import("@eox/map").EoxLayer[]} Matching layer objects.
|
|
5350
5665
|
*/
|
|
5351
5666
|
const findLayersByLayerPrefix = (layers, referenceLayer) => {
|
|
5667
|
+
if (!layers || !referenceLayer) {
|
|
5668
|
+
return [];
|
|
5669
|
+
}
|
|
5352
5670
|
const refId = referenceLayer?.properties?.id;
|
|
5353
5671
|
|
|
5354
5672
|
if (typeof refId !== "string" || !refId.includes(";:;")) {
|
|
@@ -5708,7 +6026,12 @@ function getDatetimeProperty(linksOrItems) {
|
|
|
5708
6026
|
}
|
|
5709
6027
|
|
|
5710
6028
|
// TODO: consider other properties for datetime ranges
|
|
5711
|
-
|
|
6029
|
+
|
|
6030
|
+
const datetimeProperties = /** @type {const} */ ([
|
|
6031
|
+
"datetime",
|
|
6032
|
+
"start_datetime",
|
|
6033
|
+
"end_datetime",
|
|
6034
|
+
]);
|
|
5712
6035
|
if (checkProperties) {
|
|
5713
6036
|
for (const prop of datetimeProperties) {
|
|
5714
6037
|
const propExists = linksOrItems.some(
|
|
@@ -5750,6 +6073,65 @@ function isSTACItem(stacObject) {
|
|
|
5750
6073
|
);
|
|
5751
6074
|
}
|
|
5752
6075
|
|
|
6076
|
+
/**
|
|
6077
|
+
* Fetches items using a split strategy (past/future) around a center date
|
|
6078
|
+
* @param {string} itemsUrl
|
|
6079
|
+
* @param {string} query
|
|
6080
|
+
* @param {string | Date} centerDatetime
|
|
6081
|
+
* @param {number} maxNumber
|
|
6082
|
+
* @returns {Promise<import("stac-ts").StacItem[]>}
|
|
6083
|
+
*/
|
|
6084
|
+
const fetchSplitItems = async (
|
|
6085
|
+
itemsUrl,
|
|
6086
|
+
query,
|
|
6087
|
+
centerDatetime,
|
|
6088
|
+
maxNumber,
|
|
6089
|
+
) => {
|
|
6090
|
+
const center = new Date(centerDatetime).toISOString();
|
|
6091
|
+
const limit = Math.ceil(maxNumber / 2);
|
|
6092
|
+
|
|
6093
|
+
/** @param {"past"|"future"} direction */
|
|
6094
|
+
const fetchSide = async (direction) => {
|
|
6095
|
+
const isPast = direction === "past";
|
|
6096
|
+
const datetimeRange = isPast ? `../${center}` : `${center}/..`;
|
|
6097
|
+
const sortOrder = isPast ? "-datetime" : "+datetime";
|
|
6098
|
+
const queryParams = new URLSearchParams(query);
|
|
6099
|
+
|
|
6100
|
+
queryParams.set("limit", limit.toString());
|
|
6101
|
+
queryParams.set("datetime", datetimeRange);
|
|
6102
|
+
queryParams.set("sortby", sortOrder);
|
|
6103
|
+
|
|
6104
|
+
const splitUrl = itemsUrl.split("/");
|
|
6105
|
+
const collectionId = /** @type {string} */ (splitUrl.at(-2));
|
|
6106
|
+
queryParams.set("collection", collectionId);
|
|
6107
|
+
|
|
6108
|
+
const searchEndpoint = `${splitUrl.slice(0, -3).join("/")}/search`;
|
|
6109
|
+
const items = await axios
|
|
6110
|
+
.get(searchEndpoint, { params: queryParams })
|
|
6111
|
+
.then((res) => res.data.features);
|
|
6112
|
+
return items;
|
|
6113
|
+
};
|
|
6114
|
+
|
|
6115
|
+
const [pastItems, futureItems] = await Promise.all([
|
|
6116
|
+
fetchSide("past"),
|
|
6117
|
+
fetchSide("future"),
|
|
6118
|
+
]);
|
|
6119
|
+
|
|
6120
|
+
const allItems = [...pastItems, ...futureItems];
|
|
6121
|
+
|
|
6122
|
+
// check for duplicates by ids
|
|
6123
|
+
const seen = new Set();
|
|
6124
|
+
const uniqueItems = [];
|
|
6125
|
+
for (const item of allItems) {
|
|
6126
|
+
if (!seen.has(item.id)) {
|
|
6127
|
+
seen.add(item.id);
|
|
6128
|
+
uniqueItems.push(item);
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
|
|
6132
|
+
return uniqueItems;
|
|
6133
|
+
};
|
|
6134
|
+
|
|
5753
6135
|
/**
|
|
5754
6136
|
* Fetch all STAC items from a STAC API endpoint.
|
|
5755
6137
|
* @param {string} itemsUrl
|
|
@@ -5757,6 +6139,8 @@ function isSTACItem(stacObject) {
|
|
|
5757
6139
|
* @param {number} [limit=100] - The maximum number of items to fetch per request.
|
|
5758
6140
|
* @param {boolean} [returnFirst] - If true, only the first page of results will be returned.
|
|
5759
6141
|
* @param {number} [maxNumber=1000] - if the matched number of items exceed this, only the first page will be returned.
|
|
6142
|
+
* @param {string | Date} [centerDatetime] - Date to center the search around if items exceed maxNumber
|
|
6143
|
+
* @returns {Promise<import("stac-ts").StacItem[]>}
|
|
5760
6144
|
*/
|
|
5761
6145
|
async function fetchApiItems(
|
|
5762
6146
|
itemsUrl,
|
|
@@ -5764,23 +6148,42 @@ async function fetchApiItems(
|
|
|
5764
6148
|
limit = 100,
|
|
5765
6149
|
returnFirst = false,
|
|
5766
6150
|
maxNumber = 1000,
|
|
6151
|
+
centerDatetime,
|
|
5767
6152
|
) {
|
|
5768
|
-
|
|
5769
|
-
|
|
6153
|
+
// Exclude centerDatetime from cache key - it's only used for split search fallback
|
|
6154
|
+
const cacheKey = JSON.stringify({
|
|
6155
|
+
itemsUrl,
|
|
6156
|
+
query,
|
|
6157
|
+
limit,
|
|
6158
|
+
returnFirst,
|
|
6159
|
+
maxNumber,
|
|
6160
|
+
});
|
|
6161
|
+
|
|
6162
|
+
if (itemsCache.has(cacheKey)) {
|
|
6163
|
+
return itemsCache.get(cacheKey) ?? [];
|
|
6164
|
+
}
|
|
6165
|
+
|
|
6166
|
+
const urlQuery = new URLSearchParams(query);
|
|
6167
|
+
urlQuery.set("limit", limit.toString());
|
|
6168
|
+
|
|
6169
|
+
let finalItemsUrl = itemsUrl.includes("?")
|
|
6170
|
+
? itemsUrl.split("?")[0]
|
|
6171
|
+
: itemsUrl;
|
|
6172
|
+
finalItemsUrl += urlQuery.keys().toArray().length
|
|
6173
|
+
? `?${urlQuery.toString()}`
|
|
6174
|
+
: "";
|
|
5770
6175
|
|
|
5771
6176
|
const itemsFeatureCollection = await axios
|
|
5772
|
-
.get(
|
|
6177
|
+
.get(finalItemsUrl)
|
|
5773
6178
|
.then((resp) => resp.data);
|
|
6179
|
+
|
|
5774
6180
|
/** @type {import("stac-ts").StacItem[]} */
|
|
5775
6181
|
const items = itemsFeatureCollection.features;
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
(link) => link.rel === "next",
|
|
5779
|
-
);
|
|
5780
|
-
|
|
5781
|
-
if (!nextLink || returnFirst) {
|
|
6182
|
+
if (returnFirst) {
|
|
6183
|
+
itemsCache.set(cacheKey, items);
|
|
5782
6184
|
return items;
|
|
5783
6185
|
}
|
|
6186
|
+
|
|
5784
6187
|
/** @type {number} */
|
|
5785
6188
|
const matchedItems = itemsFeatureCollection.numberMatched;
|
|
5786
6189
|
// Avoid fetching too many items
|
|
@@ -5788,26 +6191,70 @@ async function fetchApiItems(
|
|
|
5788
6191
|
console.warn(
|
|
5789
6192
|
`[eodash] The number of items matched (${matchedItems}) exceeds the maximum allowed (${maxNumber})`,
|
|
5790
6193
|
);
|
|
5791
|
-
|
|
5792
|
-
|
|
6194
|
+
// we try to narrow down the search around the center datetime
|
|
6195
|
+
if (centerDatetime) {
|
|
6196
|
+
// Check if we have a cached split result that covers this centerDatetime
|
|
6197
|
+
const splitCacheKey = JSON.stringify({ itemsUrl, query, maxNumber });
|
|
6198
|
+
const cachedSplit = splitItemsCache.get(splitCacheKey);
|
|
6199
|
+
const centerTime = new Date(centerDatetime).getTime();
|
|
5793
6200
|
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
6201
|
+
if (
|
|
6202
|
+
cachedSplit &&
|
|
6203
|
+
centerTime >= cachedSplit.minTime &&
|
|
6204
|
+
centerTime <= cachedSplit.maxTime
|
|
6205
|
+
) {
|
|
6206
|
+
return cachedSplit.items;
|
|
6207
|
+
}
|
|
5799
6208
|
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
6209
|
+
const narrowedItems = await fetchSplitItems(
|
|
6210
|
+
itemsUrl,
|
|
6211
|
+
query ?? "",
|
|
6212
|
+
centerDatetime,
|
|
6213
|
+
maxNumber,
|
|
6214
|
+
);
|
|
6215
|
+
|
|
6216
|
+
if (!narrowedItems.length) {
|
|
6217
|
+
return narrowedItems;
|
|
6218
|
+
}
|
|
6219
|
+
const datetimeProperty = getDatetimeProperty(narrowedItems);
|
|
6220
|
+
if (!datetimeProperty) {
|
|
6221
|
+
return narrowedItems;
|
|
6222
|
+
}
|
|
6223
|
+
|
|
6224
|
+
const times = narrowedItems
|
|
6225
|
+
.map((i) =>
|
|
6226
|
+
i.properties[datetimeProperty]
|
|
6227
|
+
? new Date(i.properties[datetimeProperty]).getTime()
|
|
6228
|
+
: null,
|
|
6229
|
+
)
|
|
6230
|
+
.filter((t) => t !== null);
|
|
6231
|
+
if (!times.length) {
|
|
6232
|
+
return narrowedItems;
|
|
6233
|
+
}
|
|
6234
|
+
splitItemsCache.set(splitCacheKey, {
|
|
6235
|
+
items: narrowedItems,
|
|
6236
|
+
minTime: Math.min(...times),
|
|
6237
|
+
maxTime: Math.max(...times),
|
|
6238
|
+
});
|
|
6239
|
+
|
|
6240
|
+
return narrowedItems;
|
|
5806
6241
|
}
|
|
6242
|
+
|
|
6243
|
+
itemsCache.set(cacheKey, items);
|
|
6244
|
+
return items;
|
|
5807
6245
|
}
|
|
5808
6246
|
|
|
5809
|
-
|
|
5810
|
-
|
|
6247
|
+
urlQuery.set("limit", maxNumber.toString());
|
|
6248
|
+
|
|
6249
|
+
const allItems = await axios
|
|
6250
|
+
.get(itemsUrl + "?" + urlQuery.toString())
|
|
6251
|
+
.then((resp) => resp.data.features)
|
|
6252
|
+
.catch((err) => {
|
|
6253
|
+
console.error(err);
|
|
6254
|
+
return [];
|
|
6255
|
+
});
|
|
6256
|
+
items.splice(0, items.length, ...allItems);
|
|
6257
|
+
itemsCache.set(cacheKey, items);
|
|
5811
6258
|
return items;
|
|
5812
6259
|
}
|
|
5813
6260
|
/**
|
|
@@ -5846,4 +6293,169 @@ function extractEoxLegendLink(link) {
|
|
|
5846
6293
|
return extraProperties;
|
|
5847
6294
|
}
|
|
5848
6295
|
|
|
5849
|
-
|
|
6296
|
+
/**
|
|
6297
|
+
* Locate the first sub-schema whose `format` matches by walking `properties`
|
|
6298
|
+
* and the `oneOf` / `allOf` / `anyOf` combinators. Returns the schema path
|
|
6299
|
+
* (array of keys/indices) from the root schema to the matched node, or
|
|
6300
|
+
* undefined if not found. Empty array means the input schema itself matched.
|
|
6301
|
+
*
|
|
6302
|
+
* @param {Record<string, any> | null | undefined} schema
|
|
6303
|
+
* @param {string} [format="bands"]
|
|
6304
|
+
* @returns {(string | number)[] | undefined}
|
|
6305
|
+
*/
|
|
6306
|
+
function getBandsProperty(schema, format = "bands") {
|
|
6307
|
+
if (!schema || typeof schema !== "object") return undefined;
|
|
6308
|
+
if (schema.format === format) return [];
|
|
6309
|
+
|
|
6310
|
+
if (schema.properties) {
|
|
6311
|
+
for (const key of Object.keys(schema.properties)) {
|
|
6312
|
+
const sub = getBandsProperty(schema.properties[key], format);
|
|
6313
|
+
if (sub) return ["properties", key, ...sub];
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
|
|
6317
|
+
for (const combinator of ["oneOf", "allOf", "anyOf"]) {
|
|
6318
|
+
if (!Array.isArray(schema[combinator])) continue;
|
|
6319
|
+
for (let i = 0; i < schema[combinator].length; i++) {
|
|
6320
|
+
const sub = getBandsProperty(schema[combinator][i], format);
|
|
6321
|
+
if (sub) return [combinator, i, ...sub];
|
|
6322
|
+
}
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
return undefined;
|
|
6326
|
+
}
|
|
6327
|
+
|
|
6328
|
+
/**
|
|
6329
|
+
* Checks whether a GeoZarr layer's bands changed in the jsonform output and,
|
|
6330
|
+
* if so, rebuilds the source with the new 3 selected bands.
|
|
6331
|
+
* Gamma and rescale are handled automatically by `applyUpdatedStyles` via
|
|
6332
|
+
* `updateStyleVariables` — this function only manages source reconstruction.
|
|
6333
|
+
* Uses the existing source constructor to avoid import-version mismatches.
|
|
6334
|
+
*
|
|
6335
|
+
* @param {import("ol/layer/Layer").default} olLayer - Layer from layerConfig:change event
|
|
6336
|
+
* @param {Record<string, any>} jsonformValue - Current jsonform output
|
|
6337
|
+
* @returns {boolean} true if the source was rebuilt
|
|
6338
|
+
*/
|
|
6339
|
+
function updateGeoZarrBands(olLayer, jsonformValue) {
|
|
6340
|
+
/** @type {import("@eox/map/src/layers").EOxLayerType<"WebGLTile","GeoZarr">} */
|
|
6341
|
+
const jsonLayer = olLayer.get("_jsonDefinition");
|
|
6342
|
+
const updatedBands = jsonformValue.bands;
|
|
6343
|
+
const isGeoZarr =
|
|
6344
|
+
jsonLayer?.type === "WebGLTile" && jsonLayer?.source?.type === "GeoZarr";
|
|
6345
|
+
if (!jsonLayer || !jsonLayer.source || !isGeoZarr || !updatedBands) {
|
|
6346
|
+
return false;
|
|
6347
|
+
}
|
|
6348
|
+
|
|
6349
|
+
const oldBands = jsonLayer.source?.bands;
|
|
6350
|
+
if (JSON.stringify(updatedBands) === JSON.stringify(oldBands)) {
|
|
6351
|
+
return false;
|
|
6352
|
+
}
|
|
6353
|
+
jsonLayer.source.bands = [...updatedBands];
|
|
6354
|
+
olLayer.setSource(
|
|
6355
|
+
new window.eoxMapAdvancedOlSources.GeoZarr(jsonLayer.source),
|
|
6356
|
+
);
|
|
6357
|
+
return true;
|
|
6358
|
+
}
|
|
6359
|
+
|
|
6360
|
+
/**
|
|
6361
|
+
* Applies titiler upscaling to an XYZ tile URL based on the matched endpoint config.
|
|
6362
|
+
* - titiler v1: appends `@2x` to the `{y}` tile coordinate
|
|
6363
|
+
* - titiler v2: adds `tilesize=512` query parameter (v2 removed the `@2x` suffix)
|
|
6364
|
+
* Plain strings in the config default to v1 behavior for backward compatibility.
|
|
6365
|
+
*
|
|
6366
|
+
* @param {string} url - The XYZ tile URL template
|
|
6367
|
+
* @param {Array<string | { url: string; titilerVersion?: 1 | 2 }>} upscalingEndpoints
|
|
6368
|
+
* @returns {{ url: string; tileSize: [number, number] } | null} null if no endpoint matches
|
|
6369
|
+
*/
|
|
6370
|
+
function applyTitilerUpscaling(url, upscalingEndpoints) {
|
|
6371
|
+
const match = upscalingEndpoints.find((entry) => {
|
|
6372
|
+
const endpointUrl = typeof entry === "string" ? entry : entry.url;
|
|
6373
|
+
return url.includes(endpointUrl);
|
|
6374
|
+
});
|
|
6375
|
+
|
|
6376
|
+
if (!match) {
|
|
6377
|
+
return null;
|
|
6378
|
+
}
|
|
6379
|
+
|
|
6380
|
+
const version = typeof match === "string" ? 1 : (match.titilerVersion ?? 1);
|
|
6381
|
+
|
|
6382
|
+
if (version === 2) {
|
|
6383
|
+
const [base, query] = url.split("?");
|
|
6384
|
+
const params = new URLSearchParams(query);
|
|
6385
|
+
params.set("tilesize", "512");
|
|
6386
|
+
return { url: `${base}?${params.toString()}`, tileSize: [512, 512] };
|
|
6387
|
+
}
|
|
6388
|
+
|
|
6389
|
+
return { url: url.replace("{y}", "{y}@2x"), tileSize: [512, 512] };
|
|
6390
|
+
}
|
|
6391
|
+
|
|
6392
|
+
/**
|
|
6393
|
+
* Picks the render presets for a collection, preferring the collection's own
|
|
6394
|
+
* STAC `renders` extension and falling back to client-provided config
|
|
6395
|
+
*
|
|
6396
|
+
* @param {import("stac-ts").StacCollection | null | undefined} collection
|
|
6397
|
+
* @param {Record<string, Record<string, import("@/types").Render>> | undefined} [configRenders]
|
|
6398
|
+
* @returns {Record<string, import("@/types").Render> | undefined}
|
|
6399
|
+
*/
|
|
6400
|
+
function resolveRenders(collection, configRenders) {
|
|
6401
|
+
if (collection?.renders) {
|
|
6402
|
+
return /** @type {Record<string, import("@/types").Render>} */ (
|
|
6403
|
+
collection.renders
|
|
6404
|
+
);
|
|
6405
|
+
}
|
|
6406
|
+
return collection?.id ? configRenders?.[collection.id] : undefined;
|
|
6407
|
+
}
|
|
6408
|
+
|
|
6409
|
+
/**
|
|
6410
|
+
* Serializes an object into a TiTiler query string. Arrays join with commas;
|
|
6411
|
+
* nested arrays repeat the key (e.g. `rescale: [[0,1]]` -> `rescale=0,1`);
|
|
6412
|
+
* objects are JSON-encoded. Shared by the render-extension and mosaic paths.
|
|
6413
|
+
* @param {Record<string,any>} obj
|
|
6414
|
+
* @returns {string}
|
|
6415
|
+
*/
|
|
6416
|
+
function encodeURLObject(obj) {
|
|
6417
|
+
let str = "";
|
|
6418
|
+
for (const key in obj) {
|
|
6419
|
+
const value = obj[key];
|
|
6420
|
+
if (value === null || value === undefined || value === "") {
|
|
6421
|
+
continue;
|
|
6422
|
+
}
|
|
6423
|
+
|
|
6424
|
+
const valueType = Array.isArray(value) ? "array" : typeof value;
|
|
6425
|
+
|
|
6426
|
+
switch (valueType) {
|
|
6427
|
+
case "array": {
|
|
6428
|
+
// Check if any element in the array is itself an array (multi-dimensional)
|
|
6429
|
+
const hasNestedArrays = value.some((/** @type {any} */ item) =>
|
|
6430
|
+
Array.isArray(item),
|
|
6431
|
+
);
|
|
6432
|
+
|
|
6433
|
+
if (hasNestedArrays) {
|
|
6434
|
+
// For multi-dimensional arrays, repeat the key with different values
|
|
6435
|
+
for (const val of value) {
|
|
6436
|
+
if (Array.isArray(val)) {
|
|
6437
|
+
str += `${key}=${val.join(",")}&`;
|
|
6438
|
+
} else {
|
|
6439
|
+
str += `${key}=${val}&`;
|
|
6440
|
+
}
|
|
6441
|
+
}
|
|
6442
|
+
} else {
|
|
6443
|
+
// For simple arrays, join with commas
|
|
6444
|
+
str += `${key}=${value.join(",")}&`;
|
|
6445
|
+
}
|
|
6446
|
+
break;
|
|
6447
|
+
}
|
|
6448
|
+
case "object": {
|
|
6449
|
+
str += `${key}=${encodeURI(JSON.stringify(value))}&`;
|
|
6450
|
+
break;
|
|
6451
|
+
}
|
|
6452
|
+
default: {
|
|
6453
|
+
str += `${key}=${encodeURIComponent(value)}&`;
|
|
6454
|
+
break;
|
|
6455
|
+
}
|
|
6456
|
+
}
|
|
6457
|
+
}
|
|
6458
|
+
return str;
|
|
6459
|
+
}
|
|
6460
|
+
|
|
6461
|
+
export { sanitizeBbox as $, dataThemesBrands as A, getLayers as B, extractLayerLegend as C, extractCollectionUrls as D, generateLinksFromItems as E, revokeCollectionBlobUrls as F, collectionsPalette as G, datetime as H, poi as I, activeTemplate as J, mapPosition as K, isFirstLoad as L, indicator as M, currentUrl as N, currentCompareUrl as O, eodashCompareCollections as P, compareIndicator as Q, comparePoi as R, eodashCollections as S, states as T, actions as U, areChartsSeparateLayout as V, chartSpec as W, compareChartSpec as X, loading as Y, includesProcess as Z, shouldShowChartWidget as _, extractEoxLegendLink as a, tooltipAdapter as a0, mapCompareEl as a1, updateGeoZarrBands as a2, layerControlFormValueCompare as a3, layerControlFormValue as a4, getColFromLayer as a5, isGlobe as a6, setMapProjFromCol as a7, setActiveTemplate as a8, availableMapProjection as a9, changeMapProjection as aa, getCompareLayers as ab, compareChartData as ac, chartData as ad, axios$1 as ae, removeLayers as af, resolveRenders as ag, removeUnneededProperties as ah, resolveStyle as b, createLayerID as c, extractLayerConfig as d, extractRoles as e, axios as f, applyTitilerUpscaling as g, addTooltipInteraction as h, createAssetID as i, getBandsProperty as j, fetchStyle as k, encodeURLObject as l, mergeGeojsons as m, mapEl as n, getProjectionCode as o, isSTACItem as p, extractLayerTimeValues as q, registerProjection as r, fetchApiItems as s, getDatetimeProperty as t, fetchPreAggregations as u, fetchAllStyles as v, findLayer as w, findLayersByLayerPrefix as x, replaceLayer as y, generateFeatures as z };
|