@eodash/eodash 5.0.0-alpha.1.12 → 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 +15 -11
- package/bin/utils.js +6 -2
- package/core/composables/DefineWidgets.js +17 -10
- package/core/composables/index.js +50 -2
- package/core/eodash.js +6 -33
- package/core/main.js +1 -3
- package/core/plugins/index.js +3 -0
- 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 +118 -73
- package/core/utils/eodashSTAC.js +129 -0
- package/core/utils/index.js +48 -0
- package/core/views/Dashboard.vue +14 -5
- package/core/vite-env.d.ts +11 -0
- package/package.json +15 -5
- 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
|
|
@@ -127,13 +129,15 @@ async function configureServer(server) {
|
|
|
127
129
|
|
|
128
130
|
return () => {
|
|
129
131
|
server.middlewares.use(async (req, res, next) => {
|
|
130
|
-
if (req.originalUrl === '/@fs/config.js'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
if (req.originalUrl === '/@fs/config.js') {
|
|
133
|
+
res.statusCode = 200
|
|
134
|
+
res.setHeader('Content-Type', 'text/javascript')
|
|
135
|
+
if (existsSync(runtimeConfigPath)) {
|
|
136
|
+
await readFile(runtimeConfigPath).then(runtimeConfig => {
|
|
137
|
+
res.write(runtimeConfig)
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
res.end()
|
|
137
141
|
return
|
|
138
142
|
}
|
|
139
143
|
|
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,
|
|
@@ -25,39 +21,16 @@ const eodash = reactive({
|
|
|
25
21
|
secondary: '#00417044',
|
|
26
22
|
surface: "#f0f0f0f0",
|
|
27
23
|
}
|
|
28
|
-
}
|
|
24
|
+
},
|
|
25
|
+
meta: {}
|
|
29
26
|
},
|
|
30
27
|
template: {
|
|
31
28
|
background: {
|
|
32
29
|
id: Symbol(),
|
|
30
|
+
type: "internal",
|
|
33
31
|
widget: {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class: "fill-height fill-width overflow-none",
|
|
37
|
-
center: [15, 48],
|
|
38
|
-
layers: [{ type: "Tile", source: { type: "OSM" } }],
|
|
39
|
-
},
|
|
40
|
-
tagName: 'eox-map',
|
|
41
|
-
onMounted(el, _, router) {
|
|
42
|
-
/** @type {any} */(el).zoom = router.currentRoute.value.query['z'];
|
|
43
|
-
|
|
44
|
-
mapInstance.value = /** @type {any} */(el).map;
|
|
45
|
-
|
|
46
|
-
mapInstance.value?.on('moveend', handleMoveEnd =
|
|
47
|
-
/** @param {any} evt */(evt) => {
|
|
48
|
-
router.push({
|
|
49
|
-
query: {
|
|
50
|
-
z: `${evt.map.getView().getZoom()}`
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
},
|
|
55
|
-
onUnmounted(_el, _store, _router) {
|
|
56
|
-
//@ts-expect-error
|
|
57
|
-
mapInstance.value?.un('moveend', handleMoveEnd);
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
type: 'web-component'
|
|
32
|
+
name: 'EodashMap'
|
|
33
|
+
}
|
|
61
34
|
},
|
|
62
35
|
widgets: [
|
|
63
36
|
{
|
package/core/main.js
CHANGED
package/core/plugins/index.js
CHANGED
|
@@ -11,8 +11,10 @@ import { createPinia } from 'pinia';
|
|
|
11
11
|
import eodash from '@/eodash';
|
|
12
12
|
import { eodashKey } from '@/store/Keys';
|
|
13
13
|
import store from '../store';
|
|
14
|
+
import { createHead } from '@unhead/vue'
|
|
14
15
|
|
|
15
16
|
export const pinia = createPinia();
|
|
17
|
+
const head = createHead()
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* @param {import('vue').App} app
|
|
@@ -21,6 +23,7 @@ export function registerPlugins(app) {
|
|
|
21
23
|
window.eodashStore = store;
|
|
22
24
|
|
|
23
25
|
app.use(vuetify)
|
|
26
|
+
.use(head)
|
|
24
27
|
.use(router)
|
|
25
28
|
.use(pinia)
|
|
26
29
|
.provide(eodashKey, eodash);
|
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
|
@@ -4,26 +4,41 @@ import type { StacCatalog, StacCollection, StacItem } from "stac-ts";
|
|
|
4
4
|
import type { Ref } from "vue"
|
|
5
5
|
import type { ThemeDefinition } from "vuetify/lib/index.mjs";
|
|
6
6
|
import type { Map } from "openlayers";
|
|
7
|
+
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* @group Eodash
|
|
9
10
|
*/
|
|
10
11
|
export interface WebComponentProps<T extends ExecutionTime = "compiletime"> {
|
|
11
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Imports web component file, either using a URL or an import funtion.
|
|
14
|
+
* @example
|
|
15
|
+
* importing `eox-itemfilter` web component, after installing `@eox/itemfilter` it can be
|
|
16
|
+
* referenced:
|
|
17
|
+
* ```js
|
|
18
|
+
* link: async() => import("@eox/itemfilter")
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ::: warning
|
|
22
|
+
* import maps are not available in runtime config
|
|
23
|
+
* :::
|
|
24
|
+
**/
|
|
12
25
|
link: T extends 'runtime' ? string : (string | (() => Promise<unknown>));
|
|
13
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Exported Constructor, needs to be provided if the web component is not registered in by the
|
|
28
|
+
* [link](#link) provided
|
|
29
|
+
**/
|
|
14
30
|
constructorProp?: string
|
|
15
|
-
/** Custom tag name */
|
|
16
31
|
tagName: `${string}-${string}`
|
|
17
32
|
/** Object defining all the properties and attributes of the web component */
|
|
18
33
|
properties?: Record<string, any>
|
|
19
34
|
/**
|
|
20
|
-
*
|
|
35
|
+
* Triggered when the web component is mounted in the DOM.
|
|
21
36
|
* @param el - web component
|
|
22
37
|
* @param store - return value of the core STAC pinia store in `/core/store/stac.ts`
|
|
23
38
|
*/
|
|
24
39
|
onMounted?: (el: Element | null, store: ReturnType<typeof useSTAcStore>, router: Router) => (Promise<void> | void)
|
|
25
40
|
/**
|
|
26
|
-
*
|
|
41
|
+
* Triggered when the web component is unmounted from the DOM.
|
|
27
42
|
* @param el - web component
|
|
28
43
|
* @param store - return value of the core STAC pinia store in `/core/store/stac.ts`
|
|
29
44
|
*/
|
|
@@ -38,85 +53,70 @@ export interface WidgetsContainerProps {
|
|
|
38
53
|
|
|
39
54
|
// eodash types:
|
|
40
55
|
/**
|
|
41
|
-
* Widget type: `web-component`
|
|
42
|
-
*
|
|
43
|
-
* Installed node_module web components import should be mapped in `/core/modulesMap.ts`,
|
|
44
|
-
* then setting `widget.link`:`(import-map-key)` and `node_module`:`true`
|
|
56
|
+
* Widget type: `web-component` API
|
|
57
|
+
* @group Eodash
|
|
45
58
|
*/
|
|
46
59
|
export interface WebComponentWidget<T extends ExecutionTime = "compiletime"> {
|
|
47
|
-
/**
|
|
48
|
-
* Unique Identifier, triggers rerender when using `defineWidget`
|
|
49
|
-
**/
|
|
50
60
|
id: number | string | symbol
|
|
51
|
-
/**
|
|
52
|
-
* Widget title
|
|
53
|
-
*/
|
|
54
61
|
title: string
|
|
55
62
|
/**
|
|
56
63
|
* Widget position and size.
|
|
57
64
|
*/
|
|
58
65
|
layout: {
|
|
59
66
|
/**
|
|
60
|
-
* Horizontal start position. Integer
|
|
67
|
+
* Horizontal start position. Integer between 1 and 12
|
|
61
68
|
*/
|
|
62
69
|
x: number
|
|
63
70
|
/**
|
|
64
|
-
* Vertical start position. Integer
|
|
71
|
+
* Vertical start position. Integer between 1 and 12
|
|
65
72
|
*/
|
|
66
73
|
y: number
|
|
67
74
|
/**
|
|
68
|
-
* Width. Integer
|
|
75
|
+
* Width. Integer between 1 and 12
|
|
69
76
|
*/
|
|
70
77
|
w: number
|
|
71
78
|
/**
|
|
72
|
-
* Height. Integer
|
|
79
|
+
* Height. Integer between 1 and 12
|
|
73
80
|
*/
|
|
74
81
|
h: number
|
|
75
82
|
}
|
|
76
83
|
widget: WebComponentProps<T>
|
|
77
|
-
/**
|
|
78
|
-
* Widget type
|
|
79
|
-
*/
|
|
80
84
|
type: 'web-component'
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
/**
|
|
84
|
-
* Widget type: `internal`
|
|
85
|
-
* Internal widgets are Vue components
|
|
88
|
+
* Widget type: `internal` API.
|
|
89
|
+
* Internal widgets are Vue components provided by eodash.
|
|
90
|
+
* @group Eodash
|
|
86
91
|
*/
|
|
87
92
|
export interface InternalComponentWidget {
|
|
88
|
-
/**
|
|
89
|
-
* Unique Identifier, triggers rerender when using `defineWidget`
|
|
90
|
-
**/
|
|
91
93
|
id: number | string | symbol
|
|
92
|
-
/**
|
|
93
|
-
* Widget title
|
|
94
|
-
*/
|
|
95
94
|
title: string
|
|
96
95
|
/**
|
|
97
96
|
* Widget position and size.
|
|
98
97
|
*/
|
|
99
98
|
layout: {
|
|
100
99
|
/**
|
|
101
|
-
* Horizontal start position. Integer
|
|
100
|
+
* Horizontal start position. Integer between 1 and 12
|
|
102
101
|
*/
|
|
103
102
|
x: number
|
|
104
103
|
/**
|
|
105
|
-
* Vertical start position. Integer
|
|
104
|
+
* Vertical start position. Integer between 1 and 12
|
|
106
105
|
*/
|
|
107
106
|
y: number
|
|
108
107
|
/**
|
|
109
|
-
* Width. Integer
|
|
108
|
+
* Width. Integer between 1 and 12
|
|
110
109
|
*/
|
|
111
110
|
w: number
|
|
112
111
|
/**
|
|
113
|
-
* Height. Integer
|
|
112
|
+
* Height. Integer between 1 and 12
|
|
114
113
|
*/
|
|
115
114
|
h: number
|
|
116
115
|
}
|
|
117
116
|
widget: {
|
|
118
117
|
/**
|
|
119
|
-
* Internal Vue
|
|
118
|
+
* Internal Vue Components inside the [widgets](https://github.com/eodash/eodash/tree/main/widgets) folder can be referenced
|
|
119
|
+
* using their name without the extention .vue
|
|
120
120
|
*/
|
|
121
121
|
name: string;
|
|
122
122
|
/**
|
|
@@ -124,43 +124,37 @@ export interface InternalComponentWidget {
|
|
|
124
124
|
*/
|
|
125
125
|
props?: Record<string, unknown>
|
|
126
126
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Widget type.
|
|
129
|
-
*/
|
|
130
127
|
type: 'internal'
|
|
131
128
|
}
|
|
132
129
|
|
|
133
130
|
/**
|
|
134
|
-
* Widget type: `iframe`
|
|
131
|
+
* Widget type: `iframe` API
|
|
135
132
|
* Renders an external HTML file as a widget.
|
|
136
133
|
*/
|
|
134
|
+
/**
|
|
135
|
+
* @group Eodash
|
|
136
|
+
*/
|
|
137
137
|
export interface IFrameWidget {
|
|
138
|
-
/**
|
|
139
|
-
* Unique Identifier, triggers rerender when using `defineWidget`
|
|
140
|
-
**/
|
|
141
138
|
id: number | string | symbol
|
|
142
|
-
/**
|
|
143
|
-
* Widget title
|
|
144
|
-
*/
|
|
145
139
|
title: string
|
|
146
140
|
/**
|
|
147
141
|
* Widget position and size.
|
|
148
142
|
*/
|
|
149
143
|
layout: {
|
|
150
144
|
/**
|
|
151
|
-
* Horizontal start position. Integer
|
|
145
|
+
* Horizontal start position. Integer between 1 and 12
|
|
152
146
|
*/
|
|
153
147
|
x: number
|
|
154
148
|
/**
|
|
155
|
-
* Vertical start position. Integer
|
|
149
|
+
* Vertical start position. Integer between 1 and 12
|
|
156
150
|
*/
|
|
157
151
|
y: number
|
|
158
152
|
/**
|
|
159
|
-
* Width. Integer
|
|
153
|
+
* Width. Integer between 1 and 12
|
|
160
154
|
*/
|
|
161
155
|
w: number
|
|
162
156
|
/**
|
|
163
|
-
* Height. Integer
|
|
157
|
+
* Height. Integer between 1 and 12
|
|
164
158
|
*/
|
|
165
159
|
h: number
|
|
166
160
|
}
|
|
@@ -170,11 +164,11 @@ export interface IFrameWidget {
|
|
|
170
164
|
*/
|
|
171
165
|
src: string
|
|
172
166
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Widget type
|
|
175
|
-
*/
|
|
176
167
|
type: 'iframe'
|
|
177
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* @group Eodash
|
|
171
|
+
*/
|
|
178
172
|
export interface FunctionalWidget<T extends ExecutionTime = "compiletime"> {
|
|
179
173
|
/**
|
|
180
174
|
* Provides a functional definition of the widget,
|
|
@@ -184,32 +178,42 @@ export interface FunctionalWidget<T extends ExecutionTime = "compiletime"> {
|
|
|
184
178
|
defineWidget: (selectedSTAC: StacCatalog | StacCollection | StacItem | null) => Omit<StaticWidget<T>, 'layout'>
|
|
185
179
|
layout: {
|
|
186
180
|
/**
|
|
187
|
-
* Horizontal start position. Integer
|
|
181
|
+
* Horizontal start position. Integer between 1 and 12
|
|
188
182
|
*/
|
|
189
183
|
x: number
|
|
190
184
|
/**
|
|
191
|
-
* Vertical start position. Integer
|
|
185
|
+
* Vertical start position. Integer between 1 and 12
|
|
192
186
|
*/
|
|
193
187
|
y: number
|
|
194
188
|
/**
|
|
195
|
-
* Width. Integer
|
|
189
|
+
* Width. Integer between 1 and 12
|
|
196
190
|
*/
|
|
197
191
|
w: number
|
|
198
192
|
/**
|
|
199
|
-
* Height. Integer
|
|
193
|
+
* Height. Integer between 1 and 12
|
|
200
194
|
*/
|
|
201
195
|
h: number
|
|
202
196
|
}
|
|
203
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* @group Eodash
|
|
200
|
+
*/
|
|
204
201
|
export type StaticWidget<T extends ExecutionTime = "compiletime"> = WebComponentWidget<T> | InternalComponentWidget | IFrameWidget
|
|
202
|
+
/**
|
|
203
|
+
* @group Eodash
|
|
204
|
+
*/
|
|
205
205
|
export type Widget<T extends ExecutionTime = "compiletime"> = StaticWidget<T> | FunctionalWidget<T>
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* @group Eodash
|
|
210
|
+
*/
|
|
208
211
|
export type BackgroundWidget<T extends ExecutionTime = "compiletime"> = Omit<WebComponentWidget<T>, 'layout' | 'title'> | Omit<InternalComponentWidget, 'layout' | 'title'> | Omit<IFrameWidget, 'layout' | 'title'> | Omit<FunctionalWidget, 'layout'>
|
|
209
212
|
/**
|
|
210
213
|
* Dashboard rendered widgets specification.
|
|
211
214
|
* 3 types of widgets are supported: `"iframe"`, `"internal"`, and `"web-component"`.
|
|
212
215
|
* A specific object should be provided based on the type of the widget.
|
|
216
|
+
* @group Eodash
|
|
213
217
|
*/
|
|
214
218
|
export interface Template<T extends ExecutionTime = "compiletime"> {
|
|
215
219
|
/**
|
|
@@ -226,15 +230,21 @@ export interface Template<T extends ExecutionTime = "compiletime"> {
|
|
|
226
230
|
*/
|
|
227
231
|
widgets: Widget<T>[]
|
|
228
232
|
}
|
|
229
|
-
|
|
233
|
+
/** @ignore */
|
|
230
234
|
export type ExternalURL = `${'https://' | 'http://'}${string}`;
|
|
235
|
+
/** @ignore */
|
|
231
236
|
export type InternalRoute = `/${string}`
|
|
237
|
+
/** @ignore */
|
|
232
238
|
export type StacEndpoint = `${'https://' | 'http://'}${string}/catalog.json`
|
|
233
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @group Eodash
|
|
242
|
+
*/
|
|
234
243
|
export type ExecutionTime = "runtime" | "compiletime";
|
|
235
244
|
|
|
236
245
|
/**
|
|
237
|
-
* Eodash instance
|
|
246
|
+
* Eodash instance API
|
|
247
|
+
* @group Eodash
|
|
238
248
|
*/
|
|
239
249
|
export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
240
250
|
/**
|
|
@@ -249,13 +259,7 @@ export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
|
249
259
|
* Renderes to navigation buttons on the app header.
|
|
250
260
|
**/
|
|
251
261
|
routes?: Array<{
|
|
252
|
-
/**
|
|
253
|
-
* button title
|
|
254
|
-
**/
|
|
255
262
|
title: string,
|
|
256
|
-
/**
|
|
257
|
-
* external URL or inner path to navigate to.
|
|
258
|
-
**/
|
|
259
263
|
to: ExternalURL | InternalRoute
|
|
260
264
|
}>
|
|
261
265
|
/**
|
|
@@ -263,7 +267,7 @@ export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
|
263
267
|
*/
|
|
264
268
|
brand: {
|
|
265
269
|
/**
|
|
266
|
-
* Automatically fetches the specified font family from google fonts. if the
|
|
270
|
+
* Automatically fetches the specified font family from google fonts. if the [link](#font-link) property is specified
|
|
267
271
|
* the font family will be fetched from the provided source instead.
|
|
268
272
|
*/
|
|
269
273
|
font?: {
|
|
@@ -272,7 +276,7 @@ export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
|
272
276
|
*/
|
|
273
277
|
link?: string;
|
|
274
278
|
/**
|
|
275
|
-
* Font family. Use FVD notation to include families https://github.com/typekit/fvd
|
|
279
|
+
* Font family. Use FVD notation to include families. see https://github.com/typekit/fvd
|
|
276
280
|
*/
|
|
277
281
|
family: string
|
|
278
282
|
}
|
|
@@ -292,6 +296,8 @@ export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
|
292
296
|
* Dashboard theme as a custom vuetifyJs theme.
|
|
293
297
|
*/
|
|
294
298
|
theme?: ThemeDefinition
|
|
299
|
+
|
|
300
|
+
meta?: import("@unhead/vue").UseSeoMetaInput
|
|
295
301
|
}
|
|
296
302
|
/**
|
|
297
303
|
* Template configuration
|
|
@@ -301,6 +307,9 @@ export interface Eodash<T extends ExecutionTime = "compiletime"> {
|
|
|
301
307
|
/////////
|
|
302
308
|
|
|
303
309
|
/// eodash store types
|
|
310
|
+
/**
|
|
311
|
+
* @group EodashStore
|
|
312
|
+
*/
|
|
304
313
|
export interface EodashStore {
|
|
305
314
|
/**
|
|
306
315
|
* Stateful Reactive variables
|
|
@@ -314,11 +323,16 @@ export interface EodashStore {
|
|
|
314
323
|
* OpenLayers map instance
|
|
315
324
|
*/
|
|
316
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>
|
|
317
334
|
}
|
|
318
|
-
|
|
319
|
-
actions: {
|
|
320
|
-
loadFont: (family?: string, link?: string) => Promise<string>;
|
|
321
|
-
};
|
|
335
|
+
actions: {};
|
|
322
336
|
/**
|
|
323
337
|
* Pinia store definition used to navigate the root STAC catalog.
|
|
324
338
|
*/
|
|
@@ -327,23 +341,54 @@ export interface EodashStore {
|
|
|
327
341
|
}
|
|
328
342
|
}
|
|
329
343
|
///////
|
|
344
|
+
/**
|
|
345
|
+
* Eodash server, build and setup configuration
|
|
346
|
+
* @group EodashConfig
|
|
347
|
+
*/
|
|
330
348
|
export interface EodashConfig {
|
|
331
349
|
dev?: {
|
|
350
|
+
/** serving port */
|
|
332
351
|
port?: string | number
|
|
333
352
|
host?: string | boolean
|
|
353
|
+
/** open default browser when the server starts */
|
|
334
354
|
open?: boolean
|
|
335
355
|
}
|
|
336
356
|
preview?: {
|
|
357
|
+
/** serving port */
|
|
337
358
|
port?: string | number
|
|
338
359
|
host?: string | boolean
|
|
360
|
+
/** open default browser when the server starts */
|
|
339
361
|
open?: boolean
|
|
340
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* base public path
|
|
365
|
+
*/
|
|
341
366
|
base?: string;
|
|
367
|
+
/**
|
|
368
|
+
* build target folder path
|
|
369
|
+
*/
|
|
342
370
|
outDir?: string;
|
|
371
|
+
/** path to statically served assets folder, can be set to `false`
|
|
372
|
+
* to disable serving assets statically
|
|
373
|
+
**/
|
|
343
374
|
publicDir?: string | false;
|
|
375
|
+
/**
|
|
376
|
+
* cache folder
|
|
377
|
+
*/
|
|
344
378
|
cacheDir?: string
|
|
379
|
+
/** specifies main entry file, exporting `createEodash`*/
|
|
345
380
|
entryPoint?: string
|
|
381
|
+
/**
|
|
382
|
+
* file exporting eodash client runtime config
|
|
383
|
+
*/
|
|
346
384
|
runtime?: string
|
|
385
|
+
widgets?: string
|
|
347
386
|
}
|
|
348
|
-
|
|
349
|
-
|
|
387
|
+
/**
|
|
388
|
+
* project entry point should export this function as a default
|
|
389
|
+
* to instantiate eodash
|
|
390
|
+
*
|
|
391
|
+
* @param configCallback
|
|
392
|
+
*/
|
|
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,19 +6,22 @@
|
|
|
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
|
+
import { useSeoMeta } from "@unhead/vue"
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const eodash = await useEodashRuntime()
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
useRouteParams()
|
|
20
|
+
|
|
21
|
+
const theme = useUpdateTheme('dashboardTheme', eodash.brand?.theme)
|
|
19
22
|
theme.global.name.value = 'dashboardTheme'
|
|
20
23
|
|
|
21
|
-
const fontFamily = await loadFont(
|
|
24
|
+
const fontFamily = await loadFont(eodash.brand?.font?.family, eodash.brand?.font?.link)
|
|
22
25
|
|
|
23
26
|
const { loadSTAC } = useSTAcStore()
|
|
24
27
|
await loadSTAC()
|
|
@@ -30,9 +33,15 @@ const TemplateComponent = smAndDown.value ?
|
|
|
30
33
|
const HeaderComponent = defineAsyncComponent(() => import(`@/components/Header.vue`))
|
|
31
34
|
const FooterComponent = defineAsyncComponent(() => import(`@/components/Footer.vue`))
|
|
32
35
|
const { mainRect } = useLayout()
|
|
36
|
+
|
|
37
|
+
useSeoMeta(eodash.brand.meta ?? {})
|
|
33
38
|
</script>
|
|
34
39
|
|
|
35
40
|
<style scoped lang="scss">
|
|
41
|
+
html {
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
* {
|
|
37
46
|
font-family: v-bind('fontFamily');
|
|
38
47
|
}
|
package/core/vite-env.d.ts
CHANGED
|
@@ -11,7 +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
|
}
|
|
21
|
+
declare module "stac-js" {
|
|
22
|
+
const STAC: any, Collection: any, Item: any
|
|
23
|
+
export { STAC, Collection, Item }
|
|
24
|
+
}
|
|
25
|
+
declare module "stac-js/src/http.js" {
|
|
26
|
+
const toAbsolute: any
|
|
27
|
+
export { toAbsolute }
|
|
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": [
|
|
@@ -17,25 +17,33 @@
|
|
|
17
17
|
"browser": "./core/main.js",
|
|
18
18
|
"scripts": {
|
|
19
19
|
"dev": "npx eodash dev --entryPoint core/eodash.js",
|
|
20
|
-
"build": "npx eodash build",
|
|
20
|
+
"build": "npx eodash build --entryPoint core/eodash.js",
|
|
21
21
|
"check": "vue-tsc --noEmit --skipLibCheck && eslint .",
|
|
22
22
|
"check:lint": "eslint .",
|
|
23
23
|
"check:types": "vue-tsc --noEmit --skipLibCheck",
|
|
24
24
|
"preview": "vite preview",
|
|
25
25
|
"lint": "eslint . --fix",
|
|
26
|
-
"docs:generate": "typedoc --
|
|
26
|
+
"docs:generate": "typedoc --options typedoc.config.json",
|
|
27
|
+
"docs:dev": "vitepress dev docs",
|
|
28
|
+
"docs:build": "npm run docs:generate && vitepress build docs",
|
|
29
|
+
"docs:preview": "vitepress preview docs"
|
|
27
30
|
},
|
|
28
31
|
"dependencies": {
|
|
29
32
|
"@eox/layout": "^0.1.0",
|
|
33
|
+
"@eox/map": "^1.4.0",
|
|
30
34
|
"@eox/stacinfo": "^0.3.0",
|
|
31
35
|
"@mdi/font": "7.0.96",
|
|
36
|
+
"@unhead/vue": "^1.8.20",
|
|
32
37
|
"@vitejs/plugin-vue": "^5.0.0",
|
|
38
|
+
"@web-comp/core": "^1.0.2",
|
|
39
|
+
"@web-comp/date-picker": "^1.0.8",
|
|
33
40
|
"animated-details": "gist:2912bb049fa906671807415eb0e87188",
|
|
34
41
|
"axios": "^1.6.2",
|
|
35
42
|
"commander": "^12.0.0",
|
|
36
43
|
"core-js": "^3.29.0",
|
|
37
44
|
"pinia": "^2.0.0",
|
|
38
45
|
"sass": "^1.60.0",
|
|
46
|
+
"stac-js": "^0.0.9",
|
|
39
47
|
"stac-ts": "^1.0.3",
|
|
40
48
|
"vite": "^5.1.5",
|
|
41
49
|
"vite-plugin-vuetify": "^2.0.0",
|
|
@@ -52,10 +60,12 @@
|
|
|
52
60
|
"eslint": "^8.56.0",
|
|
53
61
|
"eslint-plugin-vue": "^9.19.2",
|
|
54
62
|
"typedoc": "^0.25.7",
|
|
55
|
-
"typedoc-plugin-markdown": "^
|
|
63
|
+
"typedoc-plugin-markdown": "^4.0.0-next.54",
|
|
64
|
+
"typedoc-plugin-vue": "^1.1.0",
|
|
65
|
+
"typedoc-vitepress-theme": "^1.0.0-next.0",
|
|
56
66
|
"typescript": "^5.0.0",
|
|
57
67
|
"unplugin-fonts": "^1.0.3",
|
|
58
|
-
"
|
|
68
|
+
"vitepress": "^1.0.0",
|
|
59
69
|
"vue-eslint-parser": "^9.3.2",
|
|
60
70
|
"vue-tsc": "^1.2.0"
|
|
61
71
|
},
|
|
@@ -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>
|