changes
# Conflicts: # src/components/LeafletTest.vue
This commit is contained in:
@@ -1,48 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="height:600px; width:800px">
|
<div style="height: 600px; width: 800px">
|
||||||
<q-toolbar class="bg-primary text-white q-my-md shadow-2">
|
<l-map
|
||||||
<q-btn flat round dense icon="menu" class="q-mr-sm" />
|
@ready="onMapReady"
|
||||||
<q-separator dark vertical inset />
|
ref="mapRef"
|
||||||
<q-btn stretch flat :icon="home.icon" @click="handleFavClick(home.coords)" />
|
:zoom="zoom"
|
||||||
|
:center="center"
|
||||||
<q-space />
|
style="height: 500px; width: 100%"
|
||||||
|
@click="updateMarker"
|
||||||
<q-btn-dropdown stretch flat label="Favorites">
|
>
|
||||||
<q-list>
|
|
||||||
<q-item
|
|
||||||
v-for="fav in favorites"
|
|
||||||
:key="fav.id"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
v-close-popup
|
|
||||||
@click="handleFavClick(fav.coords)"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label>{{ fav.name }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-btn-dropdown>
|
|
||||||
</q-toolbar>
|
|
||||||
<l-map @ready="onMapReady" ref="mapRef" :zoom="zoom" :center="center" style="height: 500px; width: 100%;" @click="updateMarker">
|
|
||||||
<l-tile-layer
|
<l-tile-layer
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
layer-type="base"
|
layer-type="base"
|
||||||
name="OpenStreetMap"
|
name="OpenStreetMap"
|
||||||
@click="updateMarker($event.latlng)"
|
@click="updateMarker($event.latlng)"
|
||||||
></l-tile-layer>
|
></l-tile-layer>
|
||||||
<l-marker :lat-lng="markerLatLng" @click="handleMarkerClick"></l-marker>
|
<l-marker :lat-lng="markerLatLng" @click="handleMarkerClick"></l-marker>
|
||||||
</l-map>
|
</l-map>
|
||||||
<StatusBar />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useQuasar } from "quasar";
|
import { useQuasar } from "quasar";
|
||||||
import type { Ref} from "vue";
|
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import "leaflet/dist/leaflet.css";
|
import "leaflet/dist/leaflet.css";
|
||||||
import { LMap, LTileLayer, LMarker } from "@vue-leaflet/vue-leaflet";
|
import { LMap, LTileLayer, LMarker } from "@vue-leaflet/vue-leaflet";
|
||||||
@@ -50,36 +28,19 @@ import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
|||||||
import "leaflet-geosearch/dist/geosearch.css";
|
import "leaflet-geosearch/dist/geosearch.css";
|
||||||
import "leaflet/dist/leaflet.css";
|
import "leaflet/dist/leaflet.css";
|
||||||
import type { Map, LeafletMouseEvent } from 'leaflet';
|
import type { Map, LeafletMouseEvent } from 'leaflet';
|
||||||
|
import { useLeafletStore } from "stores/leaflet";
|
||||||
import SetLocationDialog from "components/SetLocationDialog.vue";
|
import SetLocationDialog from "components/SetLocationDialog.vue";
|
||||||
import StatusBar from "components/StatusBar.vue"
|
|
||||||
import { api } from "boot/axios";
|
import { api } from "boot/axios";
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import type { coords, SearchControlProps } from 'src/types';
|
||||||
|
|
||||||
|
const leafletStore = useLeafletStore();
|
||||||
|
const { zoom, center, markerLatLng } = storeToRefs(leafletStore);
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const mapRef = ref(null);
|
const mapRef = ref(null);
|
||||||
const zoom = ref(10);
|
|
||||||
const center: Ref<[number, number]> = ref([40.71278, -74.00594]);
|
|
||||||
const markerLatLng: Ref<[number, number]> = ref([40.71278, -74.00594]);
|
|
||||||
const responseMessage = ref("");
|
const responseMessage = ref("");
|
||||||
|
|
||||||
interface coords {
|
|
||||||
lat: number;
|
|
||||||
lng: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
const onMapReady = (map: Map) => {
|
const onMapReady = (map: Map) => {
|
||||||
const provider = new OpenStreetMapProvider();
|
const provider = new OpenStreetMapProvider();
|
||||||
const searchOptions: SearchControlProps = {
|
const searchOptions: SearchControlProps = {
|
||||||
@@ -97,7 +58,7 @@ const onMapReady = (map: Map) => {
|
|||||||
keepResult: true
|
keepResult: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchControl = new GeoSearchControl(searchOptions);
|
const searchControl = GeoSearchControl(searchOptions);
|
||||||
map.addControl(searchControl);
|
map.addControl(searchControl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,10 +84,7 @@ function handleMarkerClick(event: LeafletMouseEvent) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFavClick(coords: coords) {
|
|
||||||
center.value = [coords.lat, coords.lng];
|
|
||||||
markerLatLng.value = [coords.lat, coords.lng];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setLocation(coords: coords) {
|
async function setLocation(coords: coords) {
|
||||||
try {
|
try {
|
||||||
@@ -153,45 +111,6 @@ async function setLocation(coords: coords) {
|
|||||||
$q.notify({ type: 'negative', message: responseMessage.value });
|
$q.notify({ type: 'negative', message: responseMessage.value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const home = {
|
|
||||||
name: "Home",
|
|
||||||
coords: {
|
|
||||||
lat: 40.71278,
|
|
||||||
lng: -74.00594
|
|
||||||
},
|
|
||||||
icon: "home"
|
|
||||||
};
|
|
||||||
|
|
||||||
const favorites = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "Central Park",
|
|
||||||
coords: {
|
|
||||||
lat: 40.785091,
|
|
||||||
lng: -73.968285
|
|
||||||
},
|
|
||||||
icon: "park"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "Times Square",
|
|
||||||
coords: {
|
|
||||||
lat: 40.758896,
|
|
||||||
lng: -73.985130,
|
|
||||||
},
|
|
||||||
icon: "star"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "Empire State Building",
|
|
||||||
coords: {
|
|
||||||
lat: 40.748817,
|
|
||||||
lng: -73.985428
|
|
||||||
},
|
|
||||||
icon: "building"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
84
src/components/MenuBar.vue
Normal file
84
src/components/MenuBar.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useLeafletStore } from 'stores/leaflet';
|
||||||
|
import type { coords } from 'src/types';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
|
const leafletStore = useLeafletStore();
|
||||||
|
const { center, markerLatLng } = storeToRefs(leafletStore);
|
||||||
|
|
||||||
|
const home = {
|
||||||
|
name: 'Home',
|
||||||
|
coords: {
|
||||||
|
lat: 40.71278,
|
||||||
|
lng: -74.00594,
|
||||||
|
},
|
||||||
|
icon: 'home',
|
||||||
|
};
|
||||||
|
|
||||||
|
const favorites = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Central Park',
|
||||||
|
coords: {
|
||||||
|
lat: 40.785091,
|
||||||
|
lng: -73.968285,
|
||||||
|
},
|
||||||
|
icon: 'park',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Times Square',
|
||||||
|
coords: {
|
||||||
|
lat: 40.758896,
|
||||||
|
lng: -73.98513,
|
||||||
|
},
|
||||||
|
icon: 'star',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Empire State Building',
|
||||||
|
coords: {
|
||||||
|
lat: 40.748817,
|
||||||
|
lng: -73.985428,
|
||||||
|
},
|
||||||
|
icon: 'building',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleFavClick(coords: coords) {
|
||||||
|
center.value = [coords.lat, coords.lng];
|
||||||
|
markerLatLng.value = [coords.lat, coords.lng];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-toolbar class="bg-primary text-white">
|
||||||
|
<q-btn flat round dense icon="menu" class="q-mr-sm" />
|
||||||
|
<q-separator dark vertical inset />
|
||||||
|
<q-btn stretch flat :icon="home.icon" @click="handleFavClick(home.coords)" />
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<q-btn-dropdown stretch flat label="Favorites">
|
||||||
|
<q-list>
|
||||||
|
<q-item
|
||||||
|
v-for="fav in favorites"
|
||||||
|
:key="fav.id"
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
v-close-popup
|
||||||
|
@click="handleFavClick(fav.coords)"
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ fav.name }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
</q-toolbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -3,7 +3,9 @@
|
|||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section class="row items-center">
|
<q-card-section class="row items-center">
|
||||||
<q-avatar icon="add_location" color="primary" text-color="white" />
|
<q-avatar icon="add_location" color="primary" text-color="white" />
|
||||||
<span class="q-ml-sm"> Are you sure you want to set location to {{ lat }}, {{ lng }} ?</span>
|
<span class="q-ml-sm">
|
||||||
|
Are you sure you want to set location to {{ latitude }}, {{ longitude }} ?
|
||||||
|
</span>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn flat label="OK" color="primary" @click="onOkClick" />
|
<q-btn flat label="OK" color="primary" @click="onOkClick" />
|
||||||
@@ -18,18 +20,17 @@ import { useDialogPluginComponent } from 'quasar';
|
|||||||
|
|
||||||
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 },
|
||||||
});
|
});
|
||||||
|
|
||||||
defineEmits([
|
const latitude = props.lat;
|
||||||
...useDialogPluginComponent.emits
|
const longitude = props.lng;
|
||||||
])
|
|
||||||
|
defineEmits([...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
|
||||||
|
|
||||||
function onOkClick () {
|
function onOkClick() {
|
||||||
onDialogOK()
|
onDialogOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-toolbar class="bg-primary text-white q-my-md shadow-2">
|
<q-toolbar class="bg-primary text-white">
|
||||||
<q-badge :color="statusDev.color" rounded class="q-mr-sm" />{{ statusDev.deviceName }}
|
<q-badge :color="statusDev.color" rounded class="q-mr-sm" />{{ statusDev.deviceName }}
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-layout view="lHh lpr lFf">
|
<q-layout view="lHh lpr lFf">
|
||||||
<q-header elevated>
|
<q-header elevated>
|
||||||
<q-toolbar>
|
<MenuBar />
|
||||||
<q-btn flat dense round icon="menu" aria-label="Menu"/>
|
|
||||||
|
|
||||||
<q-toolbar-title> Quasar App </q-toolbar-title>
|
|
||||||
|
|
||||||
<div>Quasar v{{ $q.version }}</div>
|
|
||||||
</q-toolbar>
|
|
||||||
</q-header>
|
</q-header>
|
||||||
|
<q-footer elevated>
|
||||||
|
<StatusBar />
|
||||||
|
</q-footer>
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
<router-view />
|
<router-view />
|
||||||
@@ -17,4 +14,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import MenuBar from 'components/MenuBar.vue'
|
||||||
|
import StatusBar from 'components/StatusBar.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
21
src/stores/leaflet.ts
Normal file
21
src/stores/leaflet.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { defineStore, acceptHMRUpdate } from 'pinia';
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
zoom: number
|
||||||
|
center: [number, number]
|
||||||
|
markerLatLng: [number, number]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLeafletStore = defineStore('leaflet', {
|
||||||
|
state: (): State => {
|
||||||
|
return {
|
||||||
|
zoom: 10,
|
||||||
|
center: [40.71278, -74.00594],
|
||||||
|
markerLatLng: [40.71278, -74.00594],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (import.meta.hot) {
|
||||||
|
import.meta.hot.accept(acceptHMRUpdate(useLeafletStore, import.meta.hot));
|
||||||
|
}
|
||||||
23
src/types.ts
23
src/types.ts
@@ -1,3 +1,6 @@
|
|||||||
|
import type { OpenStreetMapProvider } from 'leaflet-geosearch';
|
||||||
|
|
||||||
|
|
||||||
export interface DeviceShort {
|
export interface DeviceShort {
|
||||||
udid: string | null;
|
udid: string | null;
|
||||||
connection_type: string | null;
|
connection_type: string | null;
|
||||||
@@ -21,3 +24,23 @@ export interface StatusUpdate {
|
|||||||
lockdown_untrusted_reachable?: boolean;
|
lockdown_untrusted_reachable?: boolean;
|
||||||
dtservicehub_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