@eodash/eodash 5.0.0-alpha.1.13 → 5.0.0-alpha.1.14
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/bin/serverConfig.js +6 -4
- package/bin/utils.js +6 -2
- package/core/composables/DefineWidgets.js +17 -10
- package/core/composables/index.js +50 -2
- package/core/eodash.js +4 -32
- package/core/main.js +1 -3
- package/core/store/Actions.js +0 -28
- package/core/store/States.js +10 -0
- package/core/store/stac.js +3 -1
- package/core/types.d.ts +12 -4
- package/core/utils/eodashSTAC.js +129 -0
- package/core/utils/index.js +48 -0
- package/core/views/Dashboard.vue +8 -2
- package/core/vite-env.d.ts +9 -10
- package/package.json +5 -1
- package/widgets/EodashDatePicker.vue +32 -0
- package/widgets/EodashMap.vue +54 -0
package/bin/serverConfig.js
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
cachePath, publicPath, userConfig,
|
|
10
10
|
buildTargetPath,
|
|
11
11
|
logger,
|
|
12
|
-
rootPath
|
|
12
|
+
rootPath,
|
|
13
|
+
internalWidgetsPath
|
|
13
14
|
} from "./utils.js";
|
|
14
15
|
import { readFile } from "fs/promises";
|
|
15
16
|
import { defineConfig, searchForWorkspaceRoot } from "vite"
|
|
@@ -61,7 +62,8 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
61
62
|
alias: {
|
|
62
63
|
'@': fileURLToPath(new URL('../core', import.meta.url)),
|
|
63
64
|
'^': fileURLToPath(new URL('../widgets', import.meta.url)),
|
|
64
|
-
"user:config": entryPath
|
|
65
|
+
"user:config": entryPath,
|
|
66
|
+
"user:widgets": internalWidgetsPath
|
|
65
67
|
},
|
|
66
68
|
extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
|
|
67
69
|
},
|
|
@@ -78,7 +80,7 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
78
80
|
},
|
|
79
81
|
root: fileURLToPath(new URL('..', import.meta.url)),
|
|
80
82
|
optimizeDeps: mode === "development" ? {
|
|
81
|
-
include: ["webfontloader", "vuetify", "vue", "pinia"],
|
|
83
|
+
include: ["webfontloader", "vuetify", "vue", "pinia", "stac-js", "urijs"],
|
|
82
84
|
noDiscovery: true,
|
|
83
85
|
} : {},
|
|
84
86
|
/** @type {string|false} */
|
|
@@ -100,7 +102,7 @@ export const serverConfig = /** @type {import('vite').UserConfigFnPromise}*/(def
|
|
|
100
102
|
* @type {import("vite").ServerHook}
|
|
101
103
|
*/
|
|
102
104
|
async function configureServer(server) {
|
|
103
|
-
server.watcher.add([entryPath, runtimeConfigPath])
|
|
105
|
+
server.watcher.add([entryPath, runtimeConfigPath, path.join(internalWidgetsPath, "**/*.vue")])
|
|
104
106
|
|
|
105
107
|
let updatedPath = ''
|
|
106
108
|
const loggerInfo = logger.info
|
package/bin/utils.js
CHANGED
|
@@ -21,6 +21,7 @@ const pkg = JSON.parse(
|
|
|
21
21
|
* @property {string | false} publicDir
|
|
22
22
|
* @property {string} outDir
|
|
23
23
|
* @property {string} entryPoint
|
|
24
|
+
* @property {string} widgets
|
|
24
25
|
* @property {string} cacheDir
|
|
25
26
|
* @property {string} runtime
|
|
26
27
|
* @property {string} base
|
|
@@ -33,7 +34,8 @@ cli.version(pkg.version, '-v, --version', 'output the current version')
|
|
|
33
34
|
.option('--publicDir <path>', 'path to statically served assets folder')
|
|
34
35
|
.option('--no-publicDir', 'stop serving static assets')
|
|
35
36
|
.option('--outDir <path>', 'minified output folder')
|
|
36
|
-
.option('-e, --entryPoint <path>', 'file exporting `
|
|
37
|
+
.option('-e, --entryPoint <path>', 'file exporting `createEodash`')
|
|
38
|
+
.option('-w, --widgets <path>', 'folder that contains vue components as internal widgets')
|
|
37
39
|
.option('--cacheDir <path>', 'cache folder')
|
|
38
40
|
.option('-r, --runtime <path>', 'file exporting eodash client runtime config')
|
|
39
41
|
.option('-b, --base <path>', 'base public path')
|
|
@@ -52,6 +54,7 @@ export const appPath = fileURLToPath(new URL("..", import.meta.url)),
|
|
|
52
54
|
srcPath = path.join(rootPath, "/src"),
|
|
53
55
|
runtimeConfigPath = userConfig.runtime ? path.resolve(rootPath, userConfig.runtime) : path.join(srcPath, "./runtime.js"),
|
|
54
56
|
entryPath = userConfig.entryPoint ? path.resolve(rootPath, userConfig.entryPoint) : path.join(srcPath, "/main.js"),
|
|
57
|
+
internalWidgetsPath = userConfig.widgets ? path.resolve(rootPath, userConfig.widgets) : path.join(srcPath, "widgets"),
|
|
55
58
|
dotEodashPath = path.join(rootPath, "/.eodash"),
|
|
56
59
|
buildTargetPath = userConfig.outDir ? path.resolve(rootPath, userConfig.outDir) : path.join(dotEodashPath, '/dist'),
|
|
57
60
|
cachePath = userConfig.cacheDir ? path.resolve(rootPath, userConfig.cacheDir) : path.join(dotEodashPath, 'cache');
|
|
@@ -84,6 +87,7 @@ async function getUserConfig(options, command) {
|
|
|
84
87
|
entryPoint: options.entryPoint ?? config?.entryPoint,
|
|
85
88
|
outDir: options.outDir ?? config?.outDir,
|
|
86
89
|
publicDir: options.publicDir ?? config?.publicDir,
|
|
87
|
-
runtime: options.runtime ?? config?.runtime
|
|
90
|
+
runtime: options.runtime ?? config?.runtime,
|
|
91
|
+
widgets: options.widgets ?? config?.widgets
|
|
88
92
|
}
|
|
89
93
|
}
|
|
@@ -2,8 +2,6 @@ import { defineAsyncComponent, reactive, shallowRef, watch } from 'vue'
|
|
|
2
2
|
import { useSTAcStore } from '@/store/stac'
|
|
3
3
|
import { storeToRefs } from 'pinia'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* @typedef {{
|
|
9
7
|
* component:import('vue').Component | null;
|
|
@@ -17,14 +15,24 @@ import { storeToRefs } from 'pinia'
|
|
|
17
15
|
* @typedef {import('vue').ShallowRef<DefinedWidget>} ReactiveDefinedWidget
|
|
18
16
|
*/
|
|
19
17
|
|
|
18
|
+
const internalWidgets = (() => {
|
|
19
|
+
/**
|
|
20
|
+
* @type {Record<string,() => Promise<import('vue').Component>>}
|
|
21
|
+
*/
|
|
22
|
+
const importMap = {
|
|
23
|
+
...import.meta.glob('^/**/*.vue'),
|
|
24
|
+
...import.meta.glob("user:widgets/**/*.vue")
|
|
25
|
+
}
|
|
26
|
+
for (const key in importMap) {
|
|
27
|
+
const newKey = /** @type {string} */(key.split('/').at(-1)).slice(0, -4)
|
|
28
|
+
Object.defineProperty(importMap, newKey,
|
|
29
|
+
/** @type {PropertyDescriptor} */(Object.getOwnPropertyDescriptor(importMap, key)));
|
|
30
|
+
delete importMap[key];
|
|
31
|
+
}
|
|
32
|
+
return importMap
|
|
33
|
+
})();
|
|
20
34
|
|
|
21
35
|
|
|
22
|
-
/**
|
|
23
|
-
* import map to all vue components inside `widgets` directory.
|
|
24
|
-
* @type {Record<string,() => Promise<import('vue').Component>>}
|
|
25
|
-
*/
|
|
26
|
-
const internalWidgets = import.meta.glob('^/**/*.vue')
|
|
27
|
-
|
|
28
36
|
/**
|
|
29
37
|
* Composable that converts widgets Configurations to defined imported widgets
|
|
30
38
|
* @param { (import("@/types").Widget | import("@/types").BackgroundWidget | undefined)[] |
|
|
@@ -46,7 +54,6 @@ export const useDefineWidgets = (widgetConfigs) => {
|
|
|
46
54
|
props: {},
|
|
47
55
|
title: '',
|
|
48
56
|
id: Symbol(),
|
|
49
|
-
no: '4'
|
|
50
57
|
})
|
|
51
58
|
|
|
52
59
|
if ('defineWidget' in (config ?? {})) {
|
|
@@ -84,7 +91,7 @@ const getWidgetDefinition = (config) => {
|
|
|
84
91
|
switch (config?.type) {
|
|
85
92
|
case 'internal':
|
|
86
93
|
importedWidget.component = defineAsyncComponent({
|
|
87
|
-
loader: internalWidgets[
|
|
94
|
+
loader: internalWidgets[/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.name],
|
|
88
95
|
suspensible: true
|
|
89
96
|
})
|
|
90
97
|
importedWidget.props = reactive(/** @type {import("@/types").InternalComponentWidget} **/(config)?.widget.props ?? {})
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// setup functions or vue composition api components
|
|
3
3
|
|
|
4
4
|
import { reactive } from "vue"
|
|
5
|
-
import { currentUrl } from "@/store/States"
|
|
5
|
+
import { currentUrl, datetime, mapInstance, indicator } from "@/store/States"
|
|
6
6
|
import eodashConfig from "@/eodash"
|
|
7
7
|
import { useTheme } from "vuetify/lib/framework.mjs"
|
|
8
|
-
|
|
8
|
+
import { useRouter } from "vue-router"
|
|
9
|
+
import { onMounted, onUnmounted, watch } from "vue"
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Creates an absolute URL from a relative link and assignes it to `currentUrl`
|
|
@@ -145,3 +146,50 @@ export const useUpdateTheme = (themeName, themeDefinition = {}) => {
|
|
|
145
146
|
})
|
|
146
147
|
return theme
|
|
147
148
|
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Composable that initiates route query params to store
|
|
153
|
+
* STAC related values
|
|
154
|
+
*/
|
|
155
|
+
export const useRouteParams = () => {
|
|
156
|
+
const router = useRouter()
|
|
157
|
+
/**
|
|
158
|
+
* @type {import("openlayers").EventsListenerFunctionType}
|
|
159
|
+
*/
|
|
160
|
+
const handleMoveEnd = (evt) => {
|
|
161
|
+
const map = /** @type {import("openlayers").Map | undefined} */ (/** @type {*} */ (evt).map)
|
|
162
|
+
const [x, y] = map?.getView().getCenter() ?? [0, 0]
|
|
163
|
+
const z = map?.getView().getZoom()
|
|
164
|
+
const currentQuery = router.currentRoute.value.query
|
|
165
|
+
router.push({
|
|
166
|
+
query: {
|
|
167
|
+
...currentQuery,
|
|
168
|
+
x, y, z
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
onMounted(() => {
|
|
174
|
+
watch([datetime, mapInstance, currentUrl, indicator], ([updatedDate, updatedMap, updatedUrl, updatedIndicator]) => {
|
|
175
|
+
const [x, y] = updatedMap?.getView().getCenter() ?? [0, 0]
|
|
176
|
+
const currentQuery = router.currentRoute.value.query
|
|
177
|
+
router.push({
|
|
178
|
+
query: {
|
|
179
|
+
...currentQuery,
|
|
180
|
+
indicator: updatedIndicator,
|
|
181
|
+
x,
|
|
182
|
+
y,
|
|
183
|
+
z: updatedMap?.getView().getZoom(),
|
|
184
|
+
datetime: updatedDate,
|
|
185
|
+
url: updatedUrl,
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
updatedMap?.on("moveend", handleMoveEnd)
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
onUnmounted(() => {
|
|
193
|
+
mapInstance.value?.un("moveend", handleMoveEnd)
|
|
194
|
+
})
|
|
195
|
+
}
|
package/core/eodash.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { reactive } from "vue";
|
|
2
|
-
import { currentUrl
|
|
3
|
-
/**
|
|
4
|
-
* @type {Function | null}
|
|
5
|
-
*/
|
|
6
|
-
let handleMoveEnd = null;
|
|
2
|
+
import { currentUrl } from './store/States';
|
|
7
3
|
|
|
8
4
|
/**
|
|
9
5
|
* Reactive Edoash Instance Object. provided globally in the app,
|
|
@@ -31,34 +27,10 @@ const eodash = reactive({
|
|
|
31
27
|
template: {
|
|
32
28
|
background: {
|
|
33
29
|
id: Symbol(),
|
|
30
|
+
type: "internal",
|
|
34
31
|
widget: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class: "fill-height fill-width overflow-none",
|
|
38
|
-
center: [15, 48],
|
|
39
|
-
layers: [{ type: "Tile", source: { type: "OSM" } }],
|
|
40
|
-
},
|
|
41
|
-
tagName: 'eox-map',
|
|
42
|
-
onMounted(el, _, router) {
|
|
43
|
-
/** @type {any} */(el).zoom = router.currentRoute.value.query['z'];
|
|
44
|
-
|
|
45
|
-
mapInstance.value = /** @type {any} */(el).map;
|
|
46
|
-
|
|
47
|
-
mapInstance.value?.on('moveend', handleMoveEnd =
|
|
48
|
-
/** @param {any} evt */(evt) => {
|
|
49
|
-
router.push({
|
|
50
|
-
query: {
|
|
51
|
-
z: `${evt.map.getView().getZoom()}`
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
},
|
|
56
|
-
onUnmounted(_el, _store, _router) {
|
|
57
|
-
//@ts-expect-error
|
|
58
|
-
mapInstance.value?.un('moveend', handleMoveEnd);
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
type: 'web-component'
|
|
32
|
+
name: 'EodashMap'
|
|
33
|
+
}
|
|
62
34
|
},
|
|
63
35
|
widgets: [
|
|
64
36
|
{
|
package/core/main.js
CHANGED
package/core/store/Actions.js
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* loads font in the app using `webfontloader`
|
|
3
|
-
* @param {string} [family="Roboto"]
|
|
4
|
-
* @param {string} [link]
|
|
5
|
-
* @returns {Promise<string>} - font family name
|
|
6
|
-
* @see {@link "https://github.com/typekit/webfontloader "}
|
|
7
|
-
*/
|
|
8
|
-
export const loadFont = async (family = "Roboto", link) => {
|
|
9
|
-
const WebFontLoader = (await import('webfontloader')).default;
|
|
10
|
-
if (link) {
|
|
11
|
-
WebFontLoader.load({
|
|
12
|
-
custom: {
|
|
13
|
-
// Use FVD notation to include families https://github.com/typekit/fvd
|
|
14
|
-
families: [family],
|
|
15
|
-
// Path to stylesheet that defines font-face
|
|
16
|
-
urls: [link],
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
WebFontLoader.load({
|
|
22
|
-
google: {
|
|
23
|
-
families: [family]
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
return family;
|
|
28
|
-
};
|
package/core/store/States.js
CHANGED
|
@@ -10,3 +10,13 @@ export const currentUrl = ref('');
|
|
|
10
10
|
* @type {import("vue").Ref<import('openlayers').Map | null>}
|
|
11
11
|
*/
|
|
12
12
|
export const mapInstance = ref(null);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* currently selected datetime
|
|
16
|
+
*/
|
|
17
|
+
export const datetime = ref(new Date().toISOString());
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Currently selected indicator
|
|
21
|
+
*/
|
|
22
|
+
export const indicator = ref("")
|
package/core/store/stac.js
CHANGED
|
@@ -3,6 +3,7 @@ import { inject, ref } from 'vue';
|
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { useAbsoluteUrl } from '@/composables/index';
|
|
5
5
|
import { eodashKey } from '@/store/Keys';
|
|
6
|
+
import { assignIndicator } from '@/utils';
|
|
6
7
|
|
|
7
8
|
export const useSTAcStore = defineStore('stac', () => {
|
|
8
9
|
/**
|
|
@@ -14,7 +15,7 @@ export const useSTAcStore = defineStore('stac', () => {
|
|
|
14
15
|
/**
|
|
15
16
|
* selected STAC object.
|
|
16
17
|
* @type {import('vue').Ref<import('stac-ts').StacCatalog |
|
|
17
|
-
*
|
|
18
|
+
* import('stac-ts').StacCollection |import('stac-ts').StacItem
|
|
18
19
|
* | null>}
|
|
19
20
|
*/
|
|
20
21
|
const selectedStac = ref(null);
|
|
@@ -54,6 +55,7 @@ export const useSTAcStore = defineStore('stac', () => {
|
|
|
54
55
|
|
|
55
56
|
await axios.get(absoluteUrl.value).then(resp => {
|
|
56
57
|
selectedStac.value = resp.data;
|
|
58
|
+
assignIndicator(selectedStac.value)
|
|
57
59
|
}).catch(err => console.error(err));
|
|
58
60
|
}
|
|
59
61
|
|
package/core/types.d.ts
CHANGED
|
@@ -323,10 +323,16 @@ export interface EodashStore {
|
|
|
323
323
|
* OpenLayers map instance
|
|
324
324
|
*/
|
|
325
325
|
mapInstance: Ref<Map | null>
|
|
326
|
+
/**
|
|
327
|
+
* currently selected datetime
|
|
328
|
+
*/
|
|
329
|
+
datetime: Ref<string>
|
|
330
|
+
/**
|
|
331
|
+
* Currently selected indicator
|
|
332
|
+
*/
|
|
333
|
+
indicator: Ref<string>
|
|
326
334
|
}
|
|
327
|
-
actions: {
|
|
328
|
-
loadFont: (family?: string, link?: string) => Promise<string>;
|
|
329
|
-
};
|
|
335
|
+
actions: {};
|
|
330
336
|
/**
|
|
331
337
|
* Pinia store definition used to navigate the root STAC catalog.
|
|
332
338
|
*/
|
|
@@ -376,6 +382,7 @@ export interface EodashConfig {
|
|
|
376
382
|
* file exporting eodash client runtime config
|
|
377
383
|
*/
|
|
378
384
|
runtime?: string
|
|
385
|
+
widgets?: string
|
|
379
386
|
}
|
|
380
387
|
/**
|
|
381
388
|
* project entry point should export this function as a default
|
|
@@ -383,4 +390,5 @@ export interface EodashConfig {
|
|
|
383
390
|
*
|
|
384
391
|
* @param configCallback
|
|
385
392
|
*/
|
|
386
|
-
export declare const createEodash: (configCallback: (store: EodashStore) => Eodash | Promise<Eodash>) => Eodash
|
|
393
|
+
export declare const createEodash: (configCallback: (store: EodashStore) => Eodash | Promise<Eodash>) => Promise<Eodash>
|
|
394
|
+
export declare const store: EodashStore
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Collection, Item } from 'stac-js';
|
|
2
|
+
import { toAbsolute } from 'stac-js/src/http.js';
|
|
3
|
+
|
|
4
|
+
export class EodashCollection {
|
|
5
|
+
/** @type {string | undefined} */
|
|
6
|
+
#collectionUrl = undefined;
|
|
7
|
+
#collectionStac = undefined;
|
|
8
|
+
/** @type {*} */
|
|
9
|
+
selectedItem = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} collectionUrl
|
|
13
|
+
*/
|
|
14
|
+
constructor(collectionUrl) {
|
|
15
|
+
this.#collectionUrl = collectionUrl;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @param {*} item
|
|
19
|
+
* @returns
|
|
20
|
+
* @async
|
|
21
|
+
*/
|
|
22
|
+
createLayersJson = async (item = null) => {
|
|
23
|
+
let stacItem;
|
|
24
|
+
if (item instanceof Date) {
|
|
25
|
+
// if collectionStac not yet initialized we do it here
|
|
26
|
+
if (!this.#collectionStac) {
|
|
27
|
+
const response = await fetch(this.#collectionUrl);
|
|
28
|
+
const stac = await response.json();
|
|
29
|
+
this.#collectionStac = new Collection(stac);
|
|
30
|
+
}
|
|
31
|
+
stacItem = this.getItems().sort((a, b) => {
|
|
32
|
+
//@ts-expect-error
|
|
33
|
+
const distanceA = Math.abs(new Date(a.datetime) - item);
|
|
34
|
+
//@ts-expect-error
|
|
35
|
+
const distanceB = Math.abs(new Date(b.datetime) - item);
|
|
36
|
+
return distanceA - distanceB;
|
|
37
|
+
})[0];
|
|
38
|
+
this.selectedItem = stacItem;
|
|
39
|
+
} else {
|
|
40
|
+
stacItem = item;
|
|
41
|
+
}
|
|
42
|
+
const response = await fetch(
|
|
43
|
+
stacItem
|
|
44
|
+
? toAbsolute(stacItem.href, this.#collectionUrl)
|
|
45
|
+
: this.#collectionUrl
|
|
46
|
+
);
|
|
47
|
+
const stac = await response.json();
|
|
48
|
+
|
|
49
|
+
// TODO get auxiliary layers from collection
|
|
50
|
+
let layersJson = [
|
|
51
|
+
{
|
|
52
|
+
type: 'Tile',
|
|
53
|
+
properties: {
|
|
54
|
+
id: 'OSM',
|
|
55
|
+
},
|
|
56
|
+
source: {
|
|
57
|
+
type: 'OSM',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
if (!stacItem) {
|
|
63
|
+
// no specific item was requested; render last item
|
|
64
|
+
this.#collectionStac = new Collection(stac);
|
|
65
|
+
const items = this.getItems();
|
|
66
|
+
this.selectedItem = items[items.length - 1];
|
|
67
|
+
layersJson = await this.createLayersJson(this.selectedItem);
|
|
68
|
+
return layersJson;
|
|
69
|
+
} else {
|
|
70
|
+
// specific item was requested
|
|
71
|
+
const item = new Item(stac);
|
|
72
|
+
this.selectedItem = item;
|
|
73
|
+
//@ts-expect-error
|
|
74
|
+
layersJson.unshift(this.buildJson(item));
|
|
75
|
+
return layersJson;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {*} item
|
|
81
|
+
*/
|
|
82
|
+
buildJson(item) {
|
|
83
|
+
let json;
|
|
84
|
+
// TODO implement other types, such as COG
|
|
85
|
+
if (/** @type {import('stac-ts').StacLink[]} */(item.links).find((l) => l.rel === 'wms' || l.rel === 'wmts')) {
|
|
86
|
+
json = {
|
|
87
|
+
type: 'STAC',
|
|
88
|
+
displayWebMapLink: true,
|
|
89
|
+
displayFootprint: false,
|
|
90
|
+
data: item,
|
|
91
|
+
};
|
|
92
|
+
} else {
|
|
93
|
+
// fall back to rendering the feature
|
|
94
|
+
json = {
|
|
95
|
+
type: 'Vector',
|
|
96
|
+
source: {
|
|
97
|
+
type: 'Vector',
|
|
98
|
+
url: 'data:,' + encodeURIComponent(JSON.stringify(item.geometry)),
|
|
99
|
+
format: 'GeoJSON',
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return json;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
getItems() {
|
|
108
|
+
return (
|
|
109
|
+
//@ts-expect-error
|
|
110
|
+
// eslint-disable-next-line
|
|
111
|
+
/** @type {import('stac-ts').StacLink[]}*/(this.#collectionStac?.links)
|
|
112
|
+
.filter((i) => i.rel === 'item')
|
|
113
|
+
// sort by `datetime`, where oldest is first in array
|
|
114
|
+
.sort((a, b) => ( /** @type {number} */(a.datetime) < /** @type {number} */(b.datetime) ? -1 : 1))
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getDates() {
|
|
119
|
+
return (
|
|
120
|
+
//@ts-expect-error
|
|
121
|
+
// eslint-disable-next-line
|
|
122
|
+
/** @type {import('stac-ts').StacLink[]}*/ (this.#collectionStac?.links)
|
|
123
|
+
.filter((i) => i.rel === 'item')
|
|
124
|
+
// sort by `datetime`, where oldest is first in array
|
|
125
|
+
.sort((a, b) => ( /** @type {number} */(a.datetime) < /** @type {number} */(b.datetime) ? -1 : 1))
|
|
126
|
+
.map((i) => new Date( /** @type {number} */(i.datetime)))
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { indicator } from '@/store/States';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* loads font in the app using `webfontloader`
|
|
5
|
+
* @param {string} [family="Roboto"]
|
|
6
|
+
* @param {string} [link]
|
|
7
|
+
* @returns {Promise<string>} - font family name
|
|
8
|
+
* @see {@link "https://github.com/typekit/webfontloader "}
|
|
9
|
+
*/
|
|
10
|
+
export const loadFont = async (family = "Roboto", link) => {
|
|
11
|
+
const WebFontLoader = (await import('webfontloader')).default;
|
|
12
|
+
if (link) {
|
|
13
|
+
WebFontLoader.load({
|
|
14
|
+
custom: {
|
|
15
|
+
// Use FVD notation to include families https://github.com/typekit/fvd
|
|
16
|
+
families: [family],
|
|
17
|
+
// Path to stylesheet that defines font-face
|
|
18
|
+
urls: [link],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
WebFontLoader.load({
|
|
24
|
+
google: {
|
|
25
|
+
families: [family]
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return family;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {import('stac-ts').StacCatalog | import('stac-ts').StacCollection | import('stac-ts').StacItem | null} selectedSTAC
|
|
35
|
+
* @see {@link indicator}
|
|
36
|
+
*/
|
|
37
|
+
export const assignIndicator = (selectedSTAC) => {
|
|
38
|
+
const code = /** @type {string | undefined} */ (selectedSTAC?.code);
|
|
39
|
+
const subcode = /** @type {string | string[] | undefined} */ (selectedSTAC?.subcode);
|
|
40
|
+
|
|
41
|
+
if (selectedSTAC?.code || selectedSTAC?.subcode) {
|
|
42
|
+
indicator.value = code ? code :
|
|
43
|
+
Array.isArray(subcode) ? subcode[0] : subcode ?? ""
|
|
44
|
+
} else {
|
|
45
|
+
indicator.value = ""
|
|
46
|
+
}
|
|
47
|
+
console.log(indicator.value,/** @type {string} */(selectedSTAC?.code)),/** @type {string[]} */(selectedSTAC?.subcode)
|
|
48
|
+
}
|
package/core/views/Dashboard.vue
CHANGED
|
@@ -6,16 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
8
|
import { useEodashRuntime } from "@/composables/DefineEodash";
|
|
9
|
-
import { useUpdateTheme } from "@/composables";
|
|
9
|
+
import { useRouteParams, useUpdateTheme } from "@/composables";
|
|
10
10
|
import { useSTAcStore } from '@/store/stac';
|
|
11
11
|
import { defineAsyncComponent } from "vue";
|
|
12
12
|
import { useDisplay, useLayout } from "vuetify/lib/framework.mjs";
|
|
13
|
-
import { loadFont } from '@/
|
|
13
|
+
import { loadFont } from '@/utils'
|
|
14
14
|
import { useSeoMeta } from "@unhead/vue"
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
const eodash = await useEodashRuntime()
|
|
18
18
|
|
|
19
|
+
useRouteParams()
|
|
20
|
+
|
|
19
21
|
const theme = useUpdateTheme('dashboardTheme', eodash.brand?.theme)
|
|
20
22
|
theme.global.name.value = 'dashboardTheme'
|
|
21
23
|
|
|
@@ -36,6 +38,10 @@ useSeoMeta(eodash.brand.meta ?? {})
|
|
|
36
38
|
</script>
|
|
37
39
|
|
|
38
40
|
<style scoped lang="scss">
|
|
41
|
+
html {
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
* {
|
|
40
46
|
font-family: v-bind('fontFamily');
|
|
41
47
|
}
|
package/core/vite-env.d.ts
CHANGED
|
@@ -11,19 +11,18 @@ declare interface Window {
|
|
|
11
11
|
declare module '@eox/stacinfo' {
|
|
12
12
|
export const EOxStacInfo: CustomElementConstructor
|
|
13
13
|
}
|
|
14
|
+
declare module '@eox/map' {
|
|
15
|
+
export const EOxMap: CustomElementConstructor
|
|
16
|
+
}
|
|
14
17
|
declare module 'user:config' {
|
|
15
18
|
const eodash: import("@/types").Eodash | Promise<import("@/types").Eodash>;
|
|
16
19
|
export default eodash
|
|
17
20
|
}
|
|
18
|
-
declare module
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
declare module '@eox/layercontrol' {
|
|
22
|
-
export const EOxLayerControl: CustomElementConstructor
|
|
23
|
-
}
|
|
24
|
-
declare module '@eox/timecontrol' {
|
|
25
|
-
export const EOxTimeControl: CustomElementConstructor
|
|
21
|
+
declare module "stac-js" {
|
|
22
|
+
const STAC: any, Collection: any, Item: any
|
|
23
|
+
export { STAC, Collection, Item }
|
|
26
24
|
}
|
|
27
|
-
declare module
|
|
28
|
-
|
|
25
|
+
declare module "stac-js/src/http.js" {
|
|
26
|
+
const toAbsolute: any
|
|
27
|
+
export { toAbsolute }
|
|
29
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eodash/eodash",
|
|
3
|
-
"version": "5.0.0-alpha.1.
|
|
3
|
+
"version": "5.0.0-alpha.1.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./core/types.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -30,16 +30,20 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@eox/layout": "^0.1.0",
|
|
33
|
+
"@eox/map": "^1.4.0",
|
|
33
34
|
"@eox/stacinfo": "^0.3.0",
|
|
34
35
|
"@mdi/font": "7.0.96",
|
|
35
36
|
"@unhead/vue": "^1.8.20",
|
|
36
37
|
"@vitejs/plugin-vue": "^5.0.0",
|
|
38
|
+
"@web-comp/core": "^1.0.2",
|
|
39
|
+
"@web-comp/date-picker": "^1.0.8",
|
|
37
40
|
"animated-details": "gist:2912bb049fa906671807415eb0e87188",
|
|
38
41
|
"axios": "^1.6.2",
|
|
39
42
|
"commander": "^12.0.0",
|
|
40
43
|
"core-js": "^3.29.0",
|
|
41
44
|
"pinia": "^2.0.0",
|
|
42
45
|
"sass": "^1.60.0",
|
|
46
|
+
"stac-js": "^0.0.9",
|
|
43
47
|
"stac-ts": "^1.0.3",
|
|
44
48
|
"vite": "^5.1.5",
|
|
45
49
|
"vite-plugin-vuetify": "^2.0.0",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="fill-height fill-width align-center justify-center">
|
|
3
|
+
<div v-if="inline" class="fill-height fill-width">
|
|
4
|
+
<!-- <p class="text-subtitle-1 ma-1 pa-2">currently selected date is {{ currentDate }}</p> -->
|
|
5
|
+
<v-text-field base-color="primary" density="comfortable" type="date" bg-color="surface" color="primary"
|
|
6
|
+
validate-on="input" min="1980-01-01" :max="new Date().toISOString().split(`T`)[0]" label="Select Date"
|
|
7
|
+
:value="currentDate" v-model="currentDate" />
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<v-date-picker v-else v-model="currentDate" color="primary" elevation="0" bg-color="surface" location="center"
|
|
11
|
+
class="overflow-auto fill-height fill-width" :max="new Date()" position="relative"
|
|
12
|
+
show-adjacent-months></v-date-picker>
|
|
13
|
+
</span>
|
|
14
|
+
</template>
|
|
15
|
+
<script setup>
|
|
16
|
+
import { computed } from "vue";
|
|
17
|
+
import { datetime } from "@/store/States"
|
|
18
|
+
|
|
19
|
+
const props = defineProps(["inline"])
|
|
20
|
+
const currentDate = computed({
|
|
21
|
+
get() {
|
|
22
|
+
return props.inline ? datetime.value.split("T")[0] : new Date(datetime.value) ?? new Date()
|
|
23
|
+
},
|
|
24
|
+
/** @param {Date | string} updatedDate */
|
|
25
|
+
set(updatedDate) {
|
|
26
|
+
if (props.inline) {
|
|
27
|
+
updatedDate = new Date(updatedDate) ?? new Date()
|
|
28
|
+
}
|
|
29
|
+
datetime.value = /** @type {Date} */ (updatedDate).toISOString()
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<DynamicWebComponent :link="link" tag-name="eox-map" :properties="properties" :on-mounted="onMounted"
|
|
3
|
+
:on-unmounted="onUnmounted" />
|
|
4
|
+
</template>
|
|
5
|
+
<script setup>
|
|
6
|
+
import { inject, watch } from "vue";
|
|
7
|
+
import { toAbsolute } from 'stac-js/src/http.js';
|
|
8
|
+
import { EodashCollection } from "@/utils/eodashSTAC";
|
|
9
|
+
import { eodashKey } from "@/store/Keys";
|
|
10
|
+
import { mapInstance, datetime } from "@/store/States";
|
|
11
|
+
import DynamicWebComponent from "@/components/DynamicWebComponent.vue";
|
|
12
|
+
import { storeToRefs } from "pinia";
|
|
13
|
+
import '@eox/map/dist/eox-map-advanced-layers-and-sources.js';
|
|
14
|
+
|
|
15
|
+
const eodashConfig = /** @type {import("@/types").Eodash} */ inject(eodashKey)
|
|
16
|
+
|
|
17
|
+
const properties = {
|
|
18
|
+
class: "fill-height fill-width overflow-none",
|
|
19
|
+
center: [15, 48],
|
|
20
|
+
layers: [{ type: "Tile", source: { type: "OSM" } }],
|
|
21
|
+
}
|
|
22
|
+
const link = () => import("@eox/map")
|
|
23
|
+
|
|
24
|
+
/** @type {import("openlayers").EventsListenerFunctionType}*/
|
|
25
|
+
let handleMoveEnd;
|
|
26
|
+
|
|
27
|
+
/** @type {import("@/types").WebComponentProps["onMounted"]} */
|
|
28
|
+
const onMounted = (el, store, router) => {
|
|
29
|
+
datetime.value = /** @type {string} */ (router.currentRoute.value.query["datetime"] ?? "");
|
|
30
|
+
mapInstance.value = /** @type {any} */(el).map;
|
|
31
|
+
|
|
32
|
+
const { selectedStac } = storeToRefs(store)
|
|
33
|
+
|
|
34
|
+
watch([selectedStac, datetime], async ([updatedStac, updatedTime]) => {
|
|
35
|
+
if (updatedStac) {
|
|
36
|
+
const parentCollUrl = toAbsolute(updatedStac.links[1].href, eodashConfig.stacEndpoint);
|
|
37
|
+
const childCollUrl = toAbsolute(updatedStac.links[1].href, parentCollUrl);
|
|
38
|
+
const eodash = new EodashCollection(childCollUrl);
|
|
39
|
+
if (updatedTime) {
|
|
40
|
+
/** @type {any} */(el).layers = await eodash.createLayersJson(new Date(updatedTime));
|
|
41
|
+
} else {
|
|
42
|
+
/** @type {any} */(el).layers = await eodash.createLayersJson();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, { immediate: true })
|
|
46
|
+
}
|
|
47
|
+
/** @type {import("@/types").WebComponentProps["onUnmounted"]} */
|
|
48
|
+
const onUnmounted = (_el, _store, _router) => {
|
|
49
|
+
mapInstance.value?.un('moveend', handleMoveEnd);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
</script>
|