osr proxy
This commit is contained in:
@@ -39,6 +39,7 @@ export default defineConfigWithVueTs(
|
|||||||
files: ['**/*.ts', '**/*.vue'],
|
files: ['**/*.ts', '**/*.vue'],
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
|
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
|
||||||
|
'vue/no-v-text-v-html-on-component': 'off'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// https://github.com/vuejs/eslint-config-typescript
|
// https://github.com/vuejs/eslint-config-typescript
|
||||||
|
|||||||
208
package-lock.json
generated
208
package-lock.json
generated
@@ -10,6 +10,8 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
|
"@sentry/tracing": "^7.120.4",
|
||||||
|
"@sentry/vue": "^10.47.0",
|
||||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||||
"axios": "^1.2.1",
|
"axios": "^1.2.1",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
@@ -1961,6 +1963,212 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@sentry-internal/browser-utils": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-bVFRAeJWMBcBCvJKIFCMJ1/yQToL4vPGqfmlnDZeypcxkqUDKQ/Y3ziLHXoDL2sx0lagcgU2vH1QhCQ67Aujjw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/browser-utils/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/feedback": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-pdvMmi4dQpX5S/vAAzrhHPIw3T3HjUgDNgUiCBrlp7N9/6zGO2gNPhUnNekP+CjgI/z0rvf49RLqlDenpNrMOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/feedback/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-ScdovxP7hJxgMt70+7hFvwT02GIaIUAxdEM/YPsayZBeCoAukPW8WiwztJfoKtsfPyKJ5A6f0H3PIxTPcA9Row==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "10.47.0",
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-A5OY8friSe6g8WAK4L8IeOPiEd9D3Ps40DzRH5j2f6SUja0t90mKMvHRcRf8zq0d4BkdB+JM7tjOkwxpuv8heA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/replay": "10.47.0",
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/tracing": {
|
||||||
|
"version": "7.120.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.120.4.tgz",
|
||||||
|
"integrity": "sha512-Fz5+4XCg3akeoFK+K7g+d7HqGMjmnLoY2eJlpONJmaeT9pXY7yfUyXKZMmMajdE2LxxKJgQ2YKvSCaGVamTjHw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.120.4",
|
||||||
|
"@sentry/types": "7.120.4",
|
||||||
|
"@sentry/utils": "7.120.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/browser": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-rC0agZdxKA5XWfL4VwPOr/rJMogXDqZgnVzr93YWpFn9DMZT/7LzxSJVPIJwRUjx3bFEby3PcTa3YaX7pxm1AA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "10.47.0",
|
||||||
|
"@sentry-internal/feedback": "10.47.0",
|
||||||
|
"@sentry-internal/replay": "10.47.0",
|
||||||
|
"@sentry-internal/replay-canvas": "10.47.0",
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/browser/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/core": {
|
||||||
|
"version": "7.120.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.120.4.tgz",
|
||||||
|
"integrity": "sha512-TXu3Q5kKiq8db9OXGkWyXUbIxMMuttB5vJ031yolOl5T/B69JRyAoKuojLBjRv1XX583gS1rSSoX8YXX7ATFGA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.120.4",
|
||||||
|
"@sentry/utils": "7.120.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/tracing": {
|
||||||
|
"version": "7.120.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.120.4.tgz",
|
||||||
|
"integrity": "sha512-cAtpLh23qW3hoqZJ6c36EvFki5NhFWUSK71ALHefqDXEocMlfDc9I+IGn3B/ola2D2TDEDamCy3x32vctKqOag==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/tracing": "7.120.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/types": {
|
||||||
|
"version": "7.120.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.120.4.tgz",
|
||||||
|
"integrity": "sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/utils": {
|
||||||
|
"version": "7.120.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.120.4.tgz",
|
||||||
|
"integrity": "sha512-zCKpyDIWKHwtervNK2ZlaK8mMV7gVUijAgFeJStH+CU/imcdquizV3pFLlSQYRswG+Lbyd6CT/LGRh3IbtkCFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.120.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/vue": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-zIscc2e1d70yGK4qi4nqBy87TaQBKy0aXza+PtxI9qUWelF4bw0SJoVSglbISw+eOO4y0CBxZVRibLuj0Kv1pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/browser": "10.47.0",
|
||||||
|
"@sentry/core": "10.47.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tanstack/vue-router": "^1.64.0",
|
||||||
|
"pinia": "2.x || 3.x",
|
||||||
|
"vue": "2.x || 3.x"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@tanstack/vue-router": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pinia": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/vue/node_modules/@sentry/core": {
|
||||||
|
"version": "10.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
|
||||||
|
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
|
"@sentry/tracing": "^7.120.4",
|
||||||
|
"@sentry/vue": "^10.47.0",
|
||||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||||
"axios": "^1.2.1",
|
"axios": "^1.2.1",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export default defineConfig((/* ctx */) => {
|
|||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:49151',
|
target: 'http://localhost:49151',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
// rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
},
|
},
|
||||||
'/socket.io': {
|
'/socket.io': {
|
||||||
target: 'http://localhost:49151', // Your backend WebSocket server
|
target: 'http://localhost:49151', // Your backend WebSocket server
|
||||||
@@ -134,24 +134,15 @@ export default defineConfig((/* ctx */) => {
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
// rewrite: (path) => path.replace(/^\/socket.io/, ''),
|
// rewrite: (path) => path.replace(/^\/socket.io/, ''),
|
||||||
},
|
},
|
||||||
'/osm': {
|
|
||||||
target: 'https://nominatim.openstreetmap.org',
|
|
||||||
changeOrigin: true,
|
|
||||||
rewrite: (path) => path.replace(/^\/osm/, ''),
|
|
||||||
headers: {
|
|
||||||
Referer: 'https://nominatim.openstreetmap.org/',
|
|
||||||
'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/ors': {
|
'/ors': {
|
||||||
// target: 'https://router.project-osrm.org',
|
// target: 'https://router.project-osrm.org',
|
||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:8080',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
// rewrite: (path) => path.replace(/^\/osrm/, ''),
|
// rewrite: (path) => path.replace(/^\/osrm/, ''),
|
||||||
// headers: {
|
// headers: {
|
||||||
// Referer: 'https://router.project-osrm.org/',
|
// Referer: 'https://router.project-osrm.org/',
|
||||||
// 'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)',
|
// 'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)',
|
||||||
// },
|
// },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
31
src/axios.ts
31
src/axios.ts
@@ -1,31 +0,0 @@
|
|||||||
import { defineBoot } from '#q-app/wrappers';
|
|
||||||
import axios, { type AxiosInstance } from 'axios';
|
|
||||||
|
|
||||||
declare module 'vue' {
|
|
||||||
interface ComponentCustomProperties {
|
|
||||||
$axios: AxiosInstance;
|
|
||||||
$api: AxiosInstance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Be careful when using SSR for cross-request state pollution
|
|
||||||
// due to creating a Singleton instance here;
|
|
||||||
// If any client changes this (global) instance, it might be a
|
|
||||||
// good idea to move this instance creation inside of the
|
|
||||||
// "export default () => {}" function below (which runs individually
|
|
||||||
// for each client)
|
|
||||||
const api = axios.create({ baseURL: 'http://localhost:5000/api' });
|
|
||||||
|
|
||||||
export default defineBoot(({ app }) => {
|
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
|
||||||
|
|
||||||
app.config.globalProperties.$axios = axios;
|
|
||||||
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
|
||||||
// so you won't necessarily have to import axios in each vue file
|
|
||||||
|
|
||||||
app.config.globalProperties.$api = api;
|
|
||||||
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
|
||||||
// so you can easily perform requests against your app's API
|
|
||||||
});
|
|
||||||
|
|
||||||
export { api };
|
|
||||||
18
src/boot/sentry.ts
Normal file
18
src/boot/sentry.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineBoot } from '#q-app/wrappers'
|
||||||
|
import * as Sentry from '@sentry/vue';
|
||||||
|
|
||||||
|
export default defineBoot(({ app }) => {
|
||||||
|
Sentry.init({
|
||||||
|
app,
|
||||||
|
dsn: "https://c117cc7eee3a88df9d289edc77d57c60@o4511152447553536.ingest.us.sentry.io/4511152493559808",
|
||||||
|
sendDefaultPii: true,
|
||||||
|
enableLogs: true,
|
||||||
|
integrations: [
|
||||||
|
Sentry.browserTracingIntegration(),
|
||||||
|
Sentry.replayIntegration()
|
||||||
|
],
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
replaysSessionSampleRate: 0.1,
|
||||||
|
replaysOnErrorSampleRate: 1.0,
|
||||||
|
});
|
||||||
|
})
|
||||||
102
src/components/FormattedAddress.vue
Normal file
102
src/components/FormattedAddress.vue
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
{{ formattedAddressLine1 }}
|
||||||
|
<q-inner-loading v-if="loading">
|
||||||
|
<q-spinner-dots color="primary" />
|
||||||
|
</q-inner-loading>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ formattedAddressLine2 }}
|
||||||
|
<q-inner-loading v-if="loading">
|
||||||
|
<q-spinner-dots color="primary" />
|
||||||
|
</q-inner-loading>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import type { NominatimResponse } from 'components/models';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
address: Object as () => NominatimResponse,
|
||||||
|
});
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const formattedAddressLine1 = computed(() => {
|
||||||
|
if (!loading.value && props.address) {
|
||||||
|
const formAddress: string = props.address.house_number + ' ' + props.address.road;
|
||||||
|
return formAddress;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedAddressLine2 = computed(() => {
|
||||||
|
if (!loading.value && props.address) {
|
||||||
|
const town: string = props.address.city
|
||||||
|
? props.address.city
|
||||||
|
: props.address.village
|
||||||
|
? props.address.village
|
||||||
|
: ' ';
|
||||||
|
const stateAbbr = stateAbbrevMap[props.address.state] ?? props.address.state ?? ' ';
|
||||||
|
const formAddress: string = town + ', ' + stateAbbr + ' ' + props.address.postcode;
|
||||||
|
return formAddress;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const stateAbbrevMap: Record<string, string> = {
|
||||||
|
Alabama: 'AL',
|
||||||
|
Alaska: 'AK',
|
||||||
|
Arizona: 'AZ',
|
||||||
|
Arkansas: 'AR',
|
||||||
|
California: 'CA',
|
||||||
|
Colorado: 'CO',
|
||||||
|
Connecticut: 'CT',
|
||||||
|
Delaware: 'DE',
|
||||||
|
Florida: 'FL',
|
||||||
|
Georgia: 'GA',
|
||||||
|
Hawaii: 'HI',
|
||||||
|
Idaho: 'ID',
|
||||||
|
Illinois: 'IL',
|
||||||
|
Indiana: 'IN',
|
||||||
|
Iowa: 'IA',
|
||||||
|
Kansas: 'KS',
|
||||||
|
Kentucky: 'KY',
|
||||||
|
Louisiana: 'LA',
|
||||||
|
Maine: 'ME',
|
||||||
|
Maryland: 'MD',
|
||||||
|
Massachusetts: 'MA',
|
||||||
|
Michigan: 'MI',
|
||||||
|
Minnesota: 'MN',
|
||||||
|
Mississippi: 'MS',
|
||||||
|
Missouri: 'MO',
|
||||||
|
Montana: 'MT',
|
||||||
|
Nebraska: 'NE',
|
||||||
|
Nevada: 'NV',
|
||||||
|
'New Hampshire': 'NH',
|
||||||
|
'New Jersey': 'NJ',
|
||||||
|
'New Mexico': 'NM',
|
||||||
|
'New York': 'NY',
|
||||||
|
'North Carolina': 'NC',
|
||||||
|
'North Dakota': 'ND',
|
||||||
|
Ohio: 'OH',
|
||||||
|
Oklahoma: 'OK',
|
||||||
|
Oregon: 'OR',
|
||||||
|
Pennsylvania: 'PA',
|
||||||
|
'Rhode Island': 'RI',
|
||||||
|
'South Carolina': 'SC',
|
||||||
|
'South Dakota': 'SD',
|
||||||
|
Tennessee: 'TN',
|
||||||
|
Texas: 'TX',
|
||||||
|
Utah: 'UT',
|
||||||
|
Vermont: 'VT',
|
||||||
|
Virginia: 'VA',
|
||||||
|
Washington: 'WA',
|
||||||
|
'West Virginia': 'WV',
|
||||||
|
Wisconsin: 'WI',
|
||||||
|
Wyoming: 'WY',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -245,7 +245,6 @@ export class OpenRouteServiceV2 extends L.Class {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaflet factory function (typed)
|
* Leaflet factory function (typed)
|
||||||
* Attach to L.Routing.openrouteserviceV2 so that it's callable as L.Routing.openrouteserviceV2
|
|
||||||
*/
|
*/
|
||||||
export function openrouteserviceV2(
|
export function openrouteserviceV2(
|
||||||
apiKeyOrOptions: string | ORSRequestOptions,
|
apiKeyOrOptions: string | ORSRequestOptions,
|
||||||
@@ -264,15 +263,5 @@ export function openrouteserviceV2(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type LeafletWithRouting = typeof L & {
|
// Do not mutate the ESM namespace import (`import * as L`) because it is non-extensible
|
||||||
Routing?: {
|
// in production bundles. Consumers should import and use `openrouteserviceV2` directly.
|
||||||
openrouteserviceV2?: typeof openrouteserviceV2;
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const leafletWithRouting = L as LeafletWithRouting;
|
|
||||||
if (!leafletWithRouting.Routing) {
|
|
||||||
leafletWithRouting.Routing = {};
|
|
||||||
}
|
|
||||||
leafletWithRouting.Routing.openrouteserviceV2 = openrouteserviceV2;
|
|
||||||
|
|||||||
@@ -108,18 +108,41 @@
|
|||||||
:lat-lng="safeMarkerLatLng"
|
:lat-lng="safeMarkerLatLng"
|
||||||
@click="handleMarkerClick"
|
@click="handleMarkerClick"
|
||||||
>
|
>
|
||||||
<L-Popup :options="{ closeOnClick: true }">
|
<L-Popup
|
||||||
<q-list dense seperator style="min-width: 150px" class="bg-grey-10">
|
:options="{ closeOnClick: true, closeButton: false, className: 'marker-popup' }"
|
||||||
<q-item clickable v-close-popup @click="handleAddLocation">
|
>
|
||||||
<q-item-section avatar><q-icon name="add_location" /></q-item-section>
|
<q-list dense seperator style="min-width: 100px" class="bg-grey-10">
|
||||||
|
<q-item clickable v-ripple @click="handleAddLocation">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-avatar
|
||||||
|
icon="add_location"
|
||||||
|
color="primary"
|
||||||
|
text-color="white"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
<q-item-section>Add Location</q-item-section>
|
<q-item-section>Add Location</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-close-popup @click="setStartRoute">
|
<q-item clickable v-ripple @click="setStartRoute">
|
||||||
<q-item-section avatar><q-icon name="add_location" /></q-item-section>
|
<q-item-section avatar>
|
||||||
|
<q-avatar
|
||||||
|
icon="add_location"
|
||||||
|
color="primary"
|
||||||
|
text-color="white"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
<q-item-section>Set Route Start</q-item-section>
|
<q-item-section>Set Route Start</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-close-popup @click="setEndRoute">
|
<q-item clickable v-ripple @click="setEndRoute">
|
||||||
<q-item-section avatar><q-icon name="add_location" /></q-item-section>
|
<q-item-section avatar>
|
||||||
|
<q-avatar
|
||||||
|
icon="add_location"
|
||||||
|
color="primary"
|
||||||
|
text-color="white"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
<q-item-section>Set Route End</q-item-section>
|
<q-item-section>Set Route End</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
@@ -186,7 +209,7 @@ import LRoutingMachine from 'components/LRoutingMachine.vue';
|
|||||||
import LocationMark from 'components/LocationMark.vue';
|
import LocationMark from 'components/LocationMark.vue';
|
||||||
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
||||||
import { customRouter } from 'functions/serviceURL';
|
import { customRouter } from 'functions/serviceURL';
|
||||||
import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
|
//import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
|
||||||
import { useRoutingEvents } from '../composables/useRoutingEvents';
|
import { useRoutingEvents } from '../composables/useRoutingEvents';
|
||||||
import { useMarkerContextMenu } from '../composables/useMarkerContextMenu';
|
import { useMarkerContextMenu } from '../composables/useMarkerContextMenu';
|
||||||
import type { IRouter } from 'leaflet-routing-machine';
|
import type { IRouter } from 'leaflet-routing-machine';
|
||||||
@@ -195,8 +218,7 @@ import type { IRouter } from 'leaflet-routing-machine';
|
|||||||
import type {
|
import type {
|
||||||
coords,
|
coords,
|
||||||
SearchControlProps,
|
SearchControlProps,
|
||||||
NominatimAddress,
|
// NominatimAddress,
|
||||||
routeSegments,
|
|
||||||
} from 'components/models';
|
} from 'components/models';
|
||||||
import type { LeafletMouseEvent, Map } from 'leaflet';
|
import type { LeafletMouseEvent, Map } from 'leaflet';
|
||||||
|
|
||||||
@@ -208,7 +230,7 @@ import { useLeafletStore } from 'stores/leaflet';
|
|||||||
import { favorites } from 'constants/favorites';
|
import { favorites } from 'constants/favorites';
|
||||||
|
|
||||||
const leafletStore = useLeafletStore();
|
const leafletStore = useLeafletStore();
|
||||||
const { zoom, center, markerLatLng, qLocDrawer, routeSet, routeSegments } =
|
const { zoom, center, markerLatLng, qLocDrawer, routeSet, routeDirections } =
|
||||||
storeToRefs(leafletStore);
|
storeToRefs(leafletStore);
|
||||||
|
|
||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
@@ -226,7 +248,6 @@ const $q = useQuasar();
|
|||||||
const mapRef = ref();
|
const mapRef = ref();
|
||||||
const responseMessage = ref('');
|
const responseMessage = ref('');
|
||||||
const miniState = ref(true);
|
const miniState = ref(true);
|
||||||
const loading = ref(false);
|
|
||||||
const safeCenter = computed<[number, number]>(() => {
|
const safeCenter = computed<[number, number]>(() => {
|
||||||
const lat = center.value?.[0];
|
const lat = center.value?.[0];
|
||||||
const lng = center.value?.[1];
|
const lng = center.value?.[1];
|
||||||
@@ -320,25 +341,54 @@ function updateMarker(event: LeafletMouseEvent) {
|
|||||||
center.value = [event.latlng.lat, event.latlng.lng];
|
center.value = [event.latlng.lat, event.latlng.lng];
|
||||||
}
|
}
|
||||||
|
|
||||||
function routeToQueue() {
|
function closeAllPopups() {
|
||||||
console.log('routeToQueue');
|
if (mapRef.value) {
|
||||||
if (routeSet.value.start && routeSet.value.end && routeSegments.value) {
|
// Access the Leaflet map instance directly
|
||||||
console.log('routeToQueue: start: ', routeSet.value.start);
|
mapRef.value.leafletObject.closePopup();
|
||||||
setLocation({ lat: routeSet.value.start.lat, lng: routeSet.value.start.lng }, 0);
|
|
||||||
routeSegments.value.forEach((segment: routeSegments) => {
|
|
||||||
console.log('routeToQueue: segment: ', segment);
|
|
||||||
setLocation(
|
|
||||||
{ lat: segment.toCoordinates.lat, lng: segment.toCoordinates.lng },
|
|
||||||
segment.timeSeconds,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
console.log('routeToQueue: end: ', routeSet.value.end);
|
|
||||||
setLocation({ lat: routeSet.value.end.lat, lng: routeSet.value.end.lng }, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
||||||
|
|
||||||
|
async function routeToQueue() {
|
||||||
|
if (routeSet.value.start && routeSet.value.end && routeDirections) {
|
||||||
|
if (routeDirections.value && routeDirections.value.length > 0) {
|
||||||
|
for (const direction of routeDirections.value) {
|
||||||
|
if (direction.coordinates) {
|
||||||
|
await setLocation(
|
||||||
|
{ lat: Number(direction.coordinates.lat), lng: Number(direction.coordinates.lng) },
|
||||||
|
direction.time,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* function routeToQueue() {
|
||||||
|
console.log('routeToQueue');
|
||||||
|
if (routeSet.value.start && routeSet.value.end && routeSegments) {
|
||||||
|
console.log('routeToQueue: start: ', routeSet.value.start);
|
||||||
|
setLocation(
|
||||||
|
{ lat: Number(routeSet.value.start.lat), lng: Number(routeSet.value.start.lng) },
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
if (routeSegments.value) {
|
||||||
|
routeSegments.value.forEach((segment: routeSegments) => {
|
||||||
|
console.log('routeToQueue: segment: ', segment);
|
||||||
|
setLocation(
|
||||||
|
{ lat: Number(segment.toCoordinates.lat), lng: Number(segment.toCoordinates.lng) },
|
||||||
|
segment.timeSeconds,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log('routeToQueue: end: ', routeSet.value.end);
|
||||||
|
setLocation({ lat: Number(routeSet.value.end.lat), lng: Number(routeSet.value.end.lng) }, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
function clearRoute() {
|
function clearRoute() {
|
||||||
routeSegments.value = [];
|
void leafletStore.clearRouteSegments;
|
||||||
routingOptions.waypoints = [];
|
routingOptions.waypoints = [];
|
||||||
routeSet.value.start = { lat: null, lng: null };
|
routeSet.value.start = { lat: null, lng: null };
|
||||||
routeSet.value.end = { lat: null, lng: null };
|
routeSet.value.end = { lat: null, lng: null };
|
||||||
@@ -362,47 +412,49 @@ const updateRoute = () => {
|
|||||||
const { clickedLatLng, handleMarkerClick, setStartRoute, setEndRoute } = useMarkerContextMenu(
|
const { clickedLatLng, handleMarkerClick, setStartRoute, setEndRoute } = useMarkerContextMenu(
|
||||||
routeSet,
|
routeSet,
|
||||||
updateRoute,
|
updateRoute,
|
||||||
|
closeAllPopups,
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleAddLocation() {
|
function handleAddLocation() {
|
||||||
if (clickedLatLng.value) {
|
if (clickedLatLng.value) {
|
||||||
const latlng = clickedLatLng.value;
|
const latlng = clickedLatLng.value;
|
||||||
|
closeAllPopups();
|
||||||
$q.notify(`add location...${latlng.toString()}`);
|
$q.notify(`add location...${latlng.toString()}`);
|
||||||
reverseGeocode(latlng.lat, latlng.lng)
|
// reverseGeocode(latlng.lat, latlng.lng)
|
||||||
.then((data) => {
|
// .then((data) => {
|
||||||
const NomAddress = data.address as unknown as NominatimAddress;
|
// const NomAddress = data.address as unknown as NominatimAddress;
|
||||||
$q.dialog({
|
$q.dialog({
|
||||||
component: SetLocationDialog,
|
component: SetLocationDialog,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
lat: Number(latlng.lat),
|
lat: Number(latlng.lat),
|
||||||
lng: Number(latlng.lng),
|
lng: Number(latlng.lng),
|
||||||
address: NomAddress,
|
// address: NomAddress,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.onOk((delay: number) => {
|
.onOk((delay: number) => {
|
||||||
void setLocation({ lat: Number(latlng.lat), lng: Number(latlng.lng) }, delay);
|
void setLocation({ lat: Number(latlng.lat), lng: Number(latlng.lng) }, delay);
|
||||||
console.log(
|
console.log(
|
||||||
'Confirmed location add: latitude: ' +
|
'Confirmed location add: latitude: ' +
|
||||||
latlng.lat +
|
latlng.lat +
|
||||||
', longitude: ' +
|
', longitude: ' +
|
||||||
latlng.lng +
|
latlng.lng +
|
||||||
', delay: ' +
|
', delay: ' +
|
||||||
delay,
|
delay,
|
||||||
);
|
);
|
||||||
})
|
|
||||||
.onCancel(() => {
|
|
||||||
console.log('Dialog cancelled');
|
|
||||||
})
|
|
||||||
.onDismiss(() => {
|
|
||||||
console.log('Dialog dismissed');
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.onCancel(() => {
|
||||||
console.error('Error fetching reverse geocode:', error);
|
console.log('Dialog cancelled');
|
||||||
|
})
|
||||||
|
.onDismiss(() => {
|
||||||
|
console.log('Dialog dismissed');
|
||||||
});
|
});
|
||||||
|
// })
|
||||||
|
// .catch((error) => {
|
||||||
|
// console.error('Error fetching reverse geocode:', error);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
async function reverseGeocode(lat: number, lng: number) {
|
async function reverseGeocode(lat: number, lng: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -416,29 +468,36 @@ async function reverseGeocode(lat: number, lng: number) {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
function setLocation(coords: coords, delay: number) {
|
async function setLocation(coords: coords, delay: number) {
|
||||||
let notType: string = 'positive';
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
let notType: string = 'positive';
|
||||||
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
|
try {
|
||||||
if (setCmdRsp.sts === 'error') {
|
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
|
||||||
|
if (setCmdRsp.msg) {
|
||||||
|
responseMessage.value = setCmdRsp.msg;
|
||||||
|
}
|
||||||
|
if (setCmdRsp.sts === 'error') {
|
||||||
|
notType = 'negative';
|
||||||
|
reject(new Error(setCmdRsp.msg || 'Unknown error'));
|
||||||
|
}
|
||||||
|
resolve(setCmdRsp);
|
||||||
|
} catch (error: unknown) {
|
||||||
notType = 'negative';
|
notType = 'negative';
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error('Error setting location:', error.message);
|
||||||
|
responseMessage.value = `Failed to set location: ${error.message}`;
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
console.error('Error setting location:', error);
|
||||||
|
responseMessage.value = `Failed to set location: Unknown error`;
|
||||||
|
reject(new Error('Unknown error'));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: responseMessage.value });
|
||||||
}
|
}
|
||||||
if (setCmdRsp.msg) {
|
});
|
||||||
responseMessage.value = setCmdRsp.msg;
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
notType = 'negative';
|
|
||||||
if (error instanceof Error) {
|
|
||||||
console.error('Error setting location:', error.message);
|
|
||||||
responseMessage.value = `Failed to set location: ${error.message}`;
|
|
||||||
} else {
|
|
||||||
console.error('Error setting location:', error);
|
|
||||||
responseMessage.value = `Failed to set location: Unknown error`;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
$q.notify({ type: notType, message: responseMessage.value });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoomToCoods(arg: string) {
|
function zoomToCoods(arg: string) {
|
||||||
@@ -507,4 +566,9 @@ onMounted(() => {
|
|||||||
.leafletDrawer
|
.leafletDrawer
|
||||||
background-color: $dark
|
background-color: $dark
|
||||||
color: $dark
|
color: $dark
|
||||||
|
|
||||||
|
.marker-popup .leaflet-popup-content-wrapper, .marker-popup .leaflet-popup-tip
|
||||||
|
background-color: $dark
|
||||||
|
.marker-popup .leaflet-popup-content
|
||||||
|
margin: 13px 10px 13px 10px
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,15 +2,18 @@
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useSocketioStore } from 'stores/socketio';
|
import { useSocketioStore } from 'stores/socketio';
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
import type { NominatimResponse } from 'components/models';
|
||||||
|
|
||||||
import { Icon, PinCirclePanel } from 'leaflet-extra-markers';
|
import { Icon, PinCirclePanel } from 'leaflet-extra-markers';
|
||||||
|
|
||||||
|
import FormattedAddress from 'components/FormattedAddress.vue';
|
||||||
|
|
||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore);
|
const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
address: {
|
address: {
|
||||||
type: String,
|
type: Object as () => NominatimResponse,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
latitude: {
|
latitude: {
|
||||||
@@ -52,7 +55,7 @@ const props = defineProps({
|
|||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define custom events that this component can emit
|
// Define custom events that this component can emit
|
||||||
@@ -133,7 +136,7 @@ const humanReadableDateTime = (iso: string) => {
|
|||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
const stateAbbrevMap: Record<string, string> = {
|
const stateAbbrevMap: Record<string, string> = {
|
||||||
Alabama: 'AL',
|
Alabama: 'AL',
|
||||||
Alaska: 'AK',
|
Alaska: 'AK',
|
||||||
@@ -204,6 +207,7 @@ function formatAddress(input: string): string {
|
|||||||
|
|
||||||
return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`;
|
return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
const currentIndex = computed(() => {
|
const currentIndex = computed(() => {
|
||||||
return currentLocation.value ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) : 0;
|
return currentLocation.value ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) : 0;
|
||||||
@@ -260,8 +264,8 @@ onUnmounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass">
|
<q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label
|
<q-item-label>
|
||||||
>{{ formatAddress(address) }}
|
<FormattedAddress :address="props.address" />
|
||||||
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
|
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label caption lines="1" v-if="start && simulationRunning">
|
<q-item-label caption lines="1" v-if="start && simulationRunning">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const $q = useQuasar();
|
|||||||
|
|
||||||
const leafletStore = useLeafletStore();
|
const leafletStore = useLeafletStore();
|
||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const { center, markerLatLng } = storeToRefs(leafletStore);
|
const { center, markerLatLng, zoom } = storeToRefs(leafletStore);
|
||||||
|
|
||||||
const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } =
|
const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } =
|
||||||
storeToRefs(socketStore);
|
storeToRefs(socketStore);
|
||||||
@@ -57,6 +57,7 @@ function hasSubitems(item: unknown): item is FavoriteWithSubitems {
|
|||||||
function handleFavClick(coords: coords) {
|
function handleFavClick(coords: coords) {
|
||||||
center.value = [coords.lat, coords.lng];
|
center.value = [coords.lat, coords.lng];
|
||||||
markerLatLng.value = [coords.lat, coords.lng];
|
markerLatLng.value = [coords.lat, coords.lng];
|
||||||
|
zoom.value = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTestToggle() {
|
function handleTestToggle() {
|
||||||
@@ -181,7 +182,7 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'">
|
<q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'">
|
||||||
<q-btn
|
<!-- <q-btn
|
||||||
@click="
|
@click="
|
||||||
$emit('drawer');
|
$emit('drawer');
|
||||||
leafletStore.toggleQLocDrawer();
|
leafletStore.toggleQLocDrawer();
|
||||||
@@ -192,6 +193,7 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
icon="menu"
|
icon="menu"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
/>
|
/>
|
||||||
|
-->
|
||||||
<q-separator dark inset />
|
<q-separator dark inset />
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn
|
<q-btn
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-dialog ref="dlgRef" persistent>
|
<q-dialog ref="dlgRef" persistent>
|
||||||
<q-card class="bg-secondary text-grey-1 add-loc-card">
|
<q-card class="bg-dark text-grey-1 add-loc-card q-pa-sm">
|
||||||
<q-card-section>
|
<q-toolbar>
|
||||||
<q-avatar icon="add_location" color="dark" text-color="white" />
|
<q-avatar icon="add_location" color="primary" text-color="white" />
|
||||||
<span class="text-h6"> Add Location to Queue</span>
|
<q-toolbar-title>Add Location to Queue</q-toolbar-title>
|
||||||
</q-card-section>
|
</q-toolbar>
|
||||||
<q-card-section class="q-ml-lg">
|
<q-card-section class="q-ml-lg">
|
||||||
<div class="q-mb-sm">Are you sure you want to set location to:</div>
|
<div class="q-mb-sm">Are you sure you want to set location to:</div>
|
||||||
<div class="q-ml-lg">{{ formattedAddressLine1 }}</div>
|
<div class="q-ml-lg">
|
||||||
<div class="q-ml-lg">{{ formattedAddressLine2 }}</div>
|
<formatted-address :address="address" />
|
||||||
|
<q-input
|
||||||
<q-input
|
class="q-mt-sm"
|
||||||
style="max-width: 150px"
|
style="max-width: 150px"
|
||||||
v-model.number="delay"
|
v-model.number="delay"
|
||||||
filled
|
filled
|
||||||
@keyup.enter="onOkClick"
|
@keyup.enter="onOkClick"
|
||||||
label="Delay "
|
label="Delay "
|
||||||
type="number"
|
type="number"
|
||||||
suffix="seconds"
|
suffix="seconds"
|
||||||
color="grey-4"
|
color="grey-4"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
@@ -32,42 +33,35 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDialogPluginComponent } from 'quasar';
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
import { computed, ref } from 'vue';
|
import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
|
||||||
import type { PropType } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import type { NominatimAddress } from 'components/models';
|
import FormattedAddress from 'components/FormattedAddress.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
lat: { type: Number, required: true },
|
lat: { type: Number, required: true },
|
||||||
lng: { type: Number, required: true },
|
lng: { type: Number, required: true },
|
||||||
address: { type: Object as PropType<NominatimAddress>, required: false },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const loading = ref(true);
|
||||||
const delay = ref(0);
|
const delay = ref(0);
|
||||||
|
|
||||||
defineEmits([...useDialogPluginComponent.emits]);
|
defineEmits([...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
||||||
|
|
||||||
const formattedAddressLine1 = computed(() => {
|
const address = ref();
|
||||||
if (props.address) {
|
|
||||||
const formAddress: string = props.address.house_number + ' ' + props.address.road;
|
|
||||||
return formAddress;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const formattedAddressLine2 = computed(() => {
|
onMounted(async () => {
|
||||||
if (props.address) {
|
try {
|
||||||
const town: string = props.address.city
|
loading.value = true;
|
||||||
? props.address.city
|
const response = await reverseGeocodeRateLimited(props.lat, props.lng);
|
||||||
: props.address.village
|
console.log('reverse geocode response: ', response);
|
||||||
? props.address.village
|
address.value = response;
|
||||||
: ' ';
|
} catch (error) {
|
||||||
const formAddress: string = town + ', ' + props.address.state + ' ' + props.address.postcode;
|
console.error('Error fetching reverse geocode:', error);
|
||||||
return formAddress;
|
throw error;
|
||||||
} else {
|
} finally {
|
||||||
return '';
|
loading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,25 @@ export interface CtrlAttrs {
|
|||||||
[key: string]: CtrlAttr;
|
[key: string]: CtrlAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SimulationCommands =
|
||||||
export type SimulationCommands = 'start' | 'pause' | 'resume' | 'clear' | 'end' | 'add' | 'test-mode';
|
| 'start'
|
||||||
|
| 'pause'
|
||||||
|
| 'resume'
|
||||||
|
| 'clear'
|
||||||
|
| 'end'
|
||||||
|
| 'add'
|
||||||
|
| 'test-mode';
|
||||||
|
|
||||||
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
|
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
|
||||||
|
|
||||||
export type TunnelCommands = 'start' | 'start-watcher' | 'end-watcher' | 'shutdown' | 'restart' | 'clear' | 'cancel' ;
|
export type TunnelCommands =
|
||||||
|
| 'start'
|
||||||
|
| 'start-watcher'
|
||||||
|
| 'end-watcher'
|
||||||
|
| 'shutdown'
|
||||||
|
| 'restart'
|
||||||
|
| 'clear'
|
||||||
|
| 'cancel';
|
||||||
|
|
||||||
export interface CtrlAttr {
|
export interface CtrlAttr {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -28,7 +41,7 @@ export interface DevCtrlAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LocationQueue {
|
export interface LocationQueue {
|
||||||
[key: string]: LocationMark
|
[key: string]: LocationMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LocationMark {
|
interface LocationMark {
|
||||||
@@ -37,8 +50,8 @@ interface LocationMark {
|
|||||||
longitude: number | undefined | null;
|
longitude: number | undefined | null;
|
||||||
address?: string | undefined | null;
|
address?: string | undefined | null;
|
||||||
delay?: number | undefined | null;
|
delay?: number | undefined | null;
|
||||||
start?: string | undefined | null;
|
start: string | undefined | null;
|
||||||
end?: string | undefined | null ;
|
end?: string | undefined | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SERVER TO CLIENT
|
// SERVER TO CLIENT
|
||||||
@@ -240,10 +253,10 @@ export interface SearchControlProps {
|
|||||||
|
|
||||||
export interface CurrentLocation {
|
export interface CurrentLocation {
|
||||||
loc_id: string;
|
loc_id: string;
|
||||||
latitude: number| null | undefined;
|
latitude: number | null | undefined;
|
||||||
longitude: number| null | undefined;
|
longitude: number | null | undefined;
|
||||||
// start_time?: string | null | undefined;
|
// start_time?: string | null | undefined;
|
||||||
// end_time?: string | null | undefined
|
// end_time?: string | null | undefined
|
||||||
next_move?: number | null | undefined;
|
next_move?: number | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,31 +267,29 @@ export interface NextLocation {
|
|||||||
time_at_location?: number | null;
|
time_at_location?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface NominatimReverseResponse {
|
export interface NominatimReverseResponse {
|
||||||
place_id: number
|
place_id: number;
|
||||||
licence: string
|
licence: string;
|
||||||
osm_type: string
|
osm_type: string;
|
||||||
osm_id: number
|
osm_id: number;
|
||||||
lat: string
|
lat: string;
|
||||||
lon: string
|
lon: string;
|
||||||
class: string
|
class: string;
|
||||||
type: string
|
type: string;
|
||||||
place_rank: number
|
place_rank: number;
|
||||||
importance: number
|
importance: number;
|
||||||
addresstype: string
|
addresstype: string;
|
||||||
name: string
|
name: string;
|
||||||
display_name: string
|
display_name: string;
|
||||||
address: NominatimAddress
|
address: NominatimAddress;
|
||||||
boundingbox: string[]
|
boundingbox: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NominatimAddress {
|
export interface NominatimAddress {
|
||||||
house_number: string;
|
house_number: string;
|
||||||
road: string;
|
road: string;
|
||||||
village?: string;
|
village?: string;
|
||||||
city? : string;
|
city?: string;
|
||||||
county: string;
|
county: string;
|
||||||
state: string;
|
state: string;
|
||||||
'ISO3166-2-lvl4': string;
|
'ISO3166-2-lvl4': string;
|
||||||
@@ -289,8 +300,53 @@ export interface NominatimAddress {
|
|||||||
|
|
||||||
export interface routeSegments {
|
export interface routeSegments {
|
||||||
fromWaypoint: number;
|
fromWaypoint: number;
|
||||||
toWaypoint: number,
|
toWaypoint: number;
|
||||||
distanceMeters: number,
|
distanceMeters: number;
|
||||||
timeSeconds: number,
|
timeSeconds: number;
|
||||||
toCoordinates: {lat: number, lng: number};
|
toCoordinates: LatLng;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoutesSet {
|
||||||
|
[key: string]: RouteSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LatLng {
|
||||||
|
lat: number | null | undefined;
|
||||||
|
lng: number | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface routeDirections {
|
||||||
|
dirIndex: number;
|
||||||
|
coordinateIndex: number;
|
||||||
|
text: string;
|
||||||
|
distance: number;
|
||||||
|
time: number;
|
||||||
|
coordinates: LatLng | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RouteSet {
|
||||||
|
start: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
|
||||||
|
end: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
|
||||||
|
wayPoints?: [number, number][] | [null, null] | [undefined, undefined] | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeScript Interface for Reverse Geocoding Response
|
||||||
|
export interface NominatimResponse {
|
||||||
|
house_number?: string | null | undefined;
|
||||||
|
road: string;
|
||||||
|
neighbourhood?: string | null | undefined;
|
||||||
|
suburb?: string | null | undefined;
|
||||||
|
county: string;
|
||||||
|
city?: string | null | undefined;
|
||||||
|
village?: string | null | undefined;
|
||||||
|
state: string;
|
||||||
|
'ISO3166-2-lvl4': string;
|
||||||
|
postcode: string;
|
||||||
|
country: string;
|
||||||
|
country_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NominatimRequest {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,17 +13,23 @@ type RouteSetLike = {
|
|||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useMarkerContextMenu(routeSet: Ref<RouteSetLike>, updateRoute: () => void) {
|
export function useMarkerContextMenu(
|
||||||
|
routeSet: Ref<RouteSetLike>,
|
||||||
|
updateRoute: () => void,
|
||||||
|
closeAllPopups: () => void,
|
||||||
|
) {
|
||||||
const clickedLatLng = ref<LeafLet.LatLng | null>(null);
|
const clickedLatLng = ref<LeafLet.LatLng | null>(null);
|
||||||
|
|
||||||
const handleMarkerClick = (event: LeafletMouseEvent) => {
|
const handleMarkerClick = (event: LeafletMouseEvent) => {
|
||||||
console.log('marker clicked', event);
|
console.log('marker clicked', event);
|
||||||
|
closeAllPopups();
|
||||||
clickedLatLng.value = event.latlng;
|
clickedLatLng.value = event.latlng;
|
||||||
LeafLet.DomEvent.stopPropagation(event.originalEvent);
|
LeafLet.DomEvent.stopPropagation(event.originalEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setStartRoute = () => {
|
const setStartRoute = () => {
|
||||||
if (!clickedLatLng.value) return;
|
if (!clickedLatLng.value) return;
|
||||||
|
closeAllPopups();
|
||||||
(routeSet.value as RouteSet).start = clickedLatLng.value;
|
(routeSet.value as RouteSet).start = clickedLatLng.value;
|
||||||
console.log('setStartRoute: ', routeSet.value.start);
|
console.log('setStartRoute: ', routeSet.value.start);
|
||||||
};
|
};
|
||||||
@@ -31,6 +37,7 @@ export function useMarkerContextMenu(routeSet: Ref<RouteSetLike>, updateRoute: (
|
|||||||
const setEndRoute = () => {
|
const setEndRoute = () => {
|
||||||
if (!clickedLatLng.value) return;
|
if (!clickedLatLng.value) return;
|
||||||
(routeSet.value as RouteSet).end = clickedLatLng.value;
|
(routeSet.value as RouteSet).end = clickedLatLng.value;
|
||||||
|
closeAllPopups();
|
||||||
console.log('setEndRoute: ', routeSet.value.end);
|
console.log('setEndRoute: ', routeSet.value.end);
|
||||||
updateRoute();
|
updateRoute();
|
||||||
console.log('updating Route');
|
console.log('updating Route');
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { storeToRefs } from 'pinia';
|
|||||||
const leafletStore = useLeafletStore();
|
const leafletStore = useLeafletStore();
|
||||||
const { routeSegments, routeDirections } = storeToRefs(leafletStore);
|
const { routeSegments, routeDirections } = storeToRefs(leafletStore);
|
||||||
|
|
||||||
|
|
||||||
type RouteSummary = {
|
type RouteSummary = {
|
||||||
totalDistance: number;
|
totalDistance: number;
|
||||||
totalTime: number;
|
totalTime: number;
|
||||||
@@ -17,6 +16,11 @@ type RouteWaypoint = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RouteCoordinates = {
|
||||||
|
lat: number;
|
||||||
|
lng: number;
|
||||||
|
};
|
||||||
|
|
||||||
type RouteInstructions = {
|
type RouteInstructions = {
|
||||||
text: string;
|
text: string;
|
||||||
distance: number;
|
distance: number;
|
||||||
@@ -30,6 +34,7 @@ type RouteResult = {
|
|||||||
inputWaypoints?: RouteWaypoint[];
|
inputWaypoints?: RouteWaypoint[];
|
||||||
instructions?: RouteInstructions[];
|
instructions?: RouteInstructions[];
|
||||||
waypoints?: RouteWaypoint[];
|
waypoints?: RouteWaypoint[];
|
||||||
|
coordinates?: RouteCoordinates[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useRoutingEvents() {
|
export function useRoutingEvents() {
|
||||||
@@ -50,24 +55,32 @@ export function useRoutingEvents() {
|
|||||||
toWaypoint: index + 1,
|
toWaypoint: index + 1,
|
||||||
distanceMeters: segment.totalDistance,
|
distanceMeters: segment.totalDistance,
|
||||||
timeSeconds: segment.totalTime,
|
timeSeconds: segment.totalTime,
|
||||||
toCoordinates: route.inputWaypoints?.[index + 1]?.latLng ?? null,
|
toCoordinates: route.inputWaypoints?.[index + 1]?.latLng ??
|
||||||
|
route.waypoints?.[index + 1]?.latLng ?? { lat: 0, lng: 0 },
|
||||||
}));
|
}));
|
||||||
routeSegments.value = segmentSummary;
|
if (routeSegments) {
|
||||||
|
routeSegments.value = segmentSummary;
|
||||||
|
}
|
||||||
console.log('Waypoint segment summary:', segmentSummary);
|
console.log('Waypoint segment summary:', segmentSummary);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.instructions?.length) {
|
if (route.instructions?.length) {
|
||||||
const directionsSummary = route.instructions.map((direction, inx) => ({
|
const directionsSummary = route.instructions.map((direction, inx) => ({
|
||||||
waypoint: inx,
|
dirIndex: inx,
|
||||||
|
coordinateIndex: direction.index,
|
||||||
text: direction.text,
|
text: direction.text,
|
||||||
distance: direction.distance,
|
distance: direction.distance,
|
||||||
time: direction.time,
|
time: direction.time,
|
||||||
coordinates: route.waypoints?.[direction.index],
|
coordinates: {
|
||||||
|
lat: route.coordinates?.[direction.index]?.lat,
|
||||||
|
lng: route.coordinates?.[direction.index]?.lng,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
console.log('Direction waypoint segment summary:', directionsSummary);
|
console.log('Direction waypoint segment summary:', directionsSummary);
|
||||||
routeDirections.value = directionsSummary;
|
if (routeDirections) {
|
||||||
|
routeDirections.value = directionsSummary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,26 +1,13 @@
|
|||||||
// services/nominatimService.ts
|
// services/nominatimService.ts
|
||||||
import { osm } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
import type { NominatimResponse, NominatimRequest } from 'components/models';
|
||||||
|
|
||||||
// TypeScript Interface for Reverse Geocoding Response
|
|
||||||
export interface NominatimResponse {
|
|
||||||
place_id: number;
|
|
||||||
display_name: string;
|
|
||||||
address: {
|
|
||||||
road?: string;
|
|
||||||
city?: string;
|
|
||||||
country?: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
lat: string;
|
|
||||||
lon: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const API_URL = '/reverse';
|
|
||||||
|
|
||||||
// Simple debounce to respect 1s limit
|
|
||||||
let lastRequestTime = 0;
|
let lastRequestTime = 0;
|
||||||
|
|
||||||
export const reverseGeocodeRateLimited = async (lat: number, lon: number): Promise<NominatimResponse> => {
|
export const reverseGeocodeRateLimited = async (
|
||||||
|
lat: number,
|
||||||
|
lon: number,
|
||||||
|
): Promise<NominatimResponse> => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeSinceLast = now - lastRequestTime;
|
const timeSinceLast = now - lastRequestTime;
|
||||||
|
|
||||||
@@ -28,19 +15,10 @@ export const reverseGeocodeRateLimited = async (lat: number, lon: number): Promi
|
|||||||
if (timeSinceLast < 1000) {
|
if (timeSinceLast < 1000) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000 - timeSinceLast));
|
await new Promise((resolve) => setTimeout(resolve, 1000 - timeSinceLast));
|
||||||
}
|
}
|
||||||
|
const response = await api.post<NominatimResponse>('/rev_geocode', {
|
||||||
const response = await osm.get<NominatimResponse>(API_URL, {
|
latitude: lat,
|
||||||
params: {
|
longitude: lon,
|
||||||
lat,
|
} as NominatimRequest);
|
||||||
lon,
|
|
||||||
format: 'jsonv2',
|
|
||||||
addressdetails: 1,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
// It is mandatory to set a descriptive User-Agent
|
|
||||||
'User-Agent': 'Vue3App/1.0 (your-email@example.com)',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
lastRequestTime = Date.now();
|
lastRequestTime = Date.now();
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { openrouteserviceV2 } from 'components/L.Routing.OpenRouteServiceV2';
|
import { openrouteserviceV2 } from 'components/L.Routing.OpenRouteServiceV2';
|
||||||
|
|
||||||
export const customRouter = openrouteserviceV2({
|
export const customRouter = openrouteserviceV2({
|
||||||
|
api_key: '',
|
||||||
profile: 'driving-car',
|
profile: 'driving-car',
|
||||||
geometry_simplify: true,
|
geometry_simplify: true,
|
||||||
host: '/ors',
|
host: '/api/proxy/ors/',
|
||||||
});
|
});
|
||||||
|
|
||||||
//export const customRouter = L.Routing.osrmv1({
|
//export const customRouter = L.Routing.osrmv1({
|
||||||
|
|||||||
@@ -1,37 +1,6 @@
|
|||||||
import { defineStore, acceptHMRUpdate } from 'pinia';
|
import { defineStore, acceptHMRUpdate } from 'pinia';
|
||||||
import { favorites } from 'constants/favorites'
|
import { favorites } from 'constants/favorites'
|
||||||
|
import type { RoutesSet, LatLng, routeSegments, routeDirections } from 'components/models';
|
||||||
interface RoutesSet {
|
|
||||||
[key: string]: RouteSet
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LatLng {
|
|
||||||
lat: number | null | undefined;
|
|
||||||
lng: number | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface routeSegments {
|
|
||||||
fromWaypoint: number;
|
|
||||||
toWaypoint: number;
|
|
||||||
distanceMeters: number;
|
|
||||||
timeSeconds: number;
|
|
||||||
toCoordinates: LatLng | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface routeDirections {
|
|
||||||
waypoint: number;
|
|
||||||
text: string;
|
|
||||||
distance: number;
|
|
||||||
time: number;
|
|
||||||
coordinates: LatLng | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface RouteSet {
|
|
||||||
start: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
|
|
||||||
end: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
|
|
||||||
wayPoints?: [number, number][] | [null, null] | [undefined, undefined] | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
zoom: number;
|
zoom: number;
|
||||||
@@ -39,8 +8,8 @@ interface State {
|
|||||||
markerLatLng: [number, number] | [null, null] | null;
|
markerLatLng: [number, number] | [null, null] | null;
|
||||||
qLocDrawer: boolean;
|
qLocDrawer: boolean;
|
||||||
routeSet: {
|
routeSet: {
|
||||||
start: LatLng | null | undefined;
|
start: LatLng;
|
||||||
end: LatLng | null | undefined;
|
end: LatLng;
|
||||||
wayPoints?: LatLng[] | null | undefined;
|
wayPoints?: LatLng[] | null | undefined;
|
||||||
};
|
};
|
||||||
routesSet: RoutesSet[] | null;
|
routesSet: RoutesSet[] | null;
|
||||||
@@ -60,12 +29,15 @@ export const useLeafletStore = defineStore('leaflet', {
|
|||||||
end: { lat: null, lng: null },
|
end: { lat: null, lng: null },
|
||||||
wayPoints: null,
|
wayPoints: null,
|
||||||
},
|
},
|
||||||
routesSet: null,
|
routesSet: [],
|
||||||
routeSegments: null,
|
routeSegments: [],
|
||||||
routeDirections: null,
|
routeDirections: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
clearRouteSegments() {
|
||||||
|
this.routeSegments = [];
|
||||||
|
},
|
||||||
setCenter(lat: number, lng: number) {
|
setCenter(lat: number, lng: number) {
|
||||||
this.center = [lat, lng];
|
this.center = [lat, lng];
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import type {
|
|||||||
SimulationStatus,
|
SimulationStatus,
|
||||||
} from 'components/models';
|
} from 'components/models';
|
||||||
|
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const debugLog: boolean = true;
|
const debugLog: boolean = true;
|
||||||
|
|
||||||
@@ -115,14 +114,19 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log('event: simulation_status received: ', data);
|
console.log('event: simulation_status received: ', data);
|
||||||
}
|
}
|
||||||
console.log('updating currentLocation', data)
|
console.log('updating currentLocation', data);
|
||||||
this.currentLocation = {
|
this.currentLocation = {
|
||||||
loc_id: data.loc_id,
|
loc_id: data.loc_id,
|
||||||
latitude: data.latitude,
|
latitude: data.latitude,
|
||||||
longitude: data.longitude,
|
longitude: data.longitude,
|
||||||
next_move: data.next_move,
|
next_move: data.next_move,
|
||||||
};
|
};
|
||||||
this.locationQueueData[data.loc_id]['start'] = data.start;
|
if (data.start) {
|
||||||
|
const queueItem = this.locationQueueData[data.loc_id];
|
||||||
|
if (queueItem) {
|
||||||
|
queueItem.start = data.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('icloud_2fa_request', (callback) => {
|
socket.on('icloud_2fa_request', (callback) => {
|
||||||
@@ -226,7 +230,8 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
||||||
this.icloudMonitor = true;
|
this.icloudMonitor = true;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'stop':
|
case 'stop':
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
@@ -258,7 +263,8 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
||||||
this.icloudMonitor = false;
|
this.icloudMonitor = false;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'status':
|
case 'status':
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
@@ -289,11 +295,14 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'iCloud Monitor Enabled: ' +
|
'iCloud Monitor Enabled: ' +
|
||||||
response.icloud_monitor_enabled +
|
response.icloud_monitor_enabled +
|
||||||
'iCloud Monitor Running: ' +
|
'iCloud Monitor Running: ' +
|
||||||
response.icloud_monitor_running
|
response.icloud_monitor_running,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.icloudMonitor = !!(response.icloud_monitor_enabled && response.icloud_monitor_running);
|
this.icloudMonitor = !!(
|
||||||
});
|
response.icloud_monitor_enabled && response.icloud_monitor_running
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
||||||
@@ -430,9 +439,9 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
// if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
// if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
||||||
// throw new Error('Simulation is not running');
|
// throw new Error('Simulation is not running');
|
||||||
// }
|
// }
|
||||||
if (!latitude || !longitude) {
|
if (!latitude || !longitude) {
|
||||||
throw new Error('latitude or longitude not set');
|
throw new Error('latitude or longitude not set');
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/types.ts
46
src/types.ts
@@ -1,46 +0,0 @@
|
|||||||
import type { OpenStreetMapProvider } from 'leaflet-geosearch';
|
|
||||||
|
|
||||||
|
|
||||||
export interface DeviceShort {
|
|
||||||
udid: string | null;
|
|
||||||
connection_type: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StatusUpdate {
|
|
||||||
device_connected: boolean;
|
|
||||||
device_count: number;
|
|
||||||
// devices?: Array<DeviceShort>;
|
|
||||||
udid?: string | null;
|
|
||||||
device_name?: string | null;
|
|
||||||
product_version?: string | null;
|
|
||||||
phone_number?: string | null;
|
|
||||||
developer_mode_enabled?: boolean;
|
|
||||||
ddi_mounted?: boolean;
|
|
||||||
rsd_address?: string | null;
|
|
||||||
rsd_port?: number;
|
|
||||||
lockdown_trusted_port?: number;
|
|
||||||
lockdown_untrusted_port?: number;
|
|
||||||
lockdown_trusted_reachable?: boolean;
|
|
||||||
lockdown_untrusted_reachable?: boolean;
|
|
||||||
dtservicehub_reachable?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface coords {
|
|
||||||
lat: number;
|
|
||||||
lng: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SearchControlProps {
|
|
||||||
provider: OpenStreetMapProvider;
|
|
||||||
showMarker: boolean;
|
|
||||||
autoClose: boolean;
|
|
||||||
updateMap: boolean;
|
|
||||||
showPopup: boolean;
|
|
||||||
style: 'button' | 'bar';
|
|
||||||
acceptAutoLoad: boolean;
|
|
||||||
autoComplete: boolean;
|
|
||||||
autoCompleteDelay: number;
|
|
||||||
retainZoomLevel: boolean;
|
|
||||||
animateZoom: boolean;
|
|
||||||
keepResult: boolean;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user