extensive changes

This commit is contained in:
2026-03-27 17:11:13 -04:00
parent 3f3a5136eb
commit 05e63a28f1
14 changed files with 1431 additions and 508 deletions

View File

@@ -1,64 +1,168 @@
<template>
<div style="height: 600px; width: 800px; color: #000000">
<L-Map
@ready="onMapReady"
ref="mapRef"
:zoom="zoom"
:center="center"
style="height: 500px; width: 100%"
@click="updateMarker"
<div class="q-pa-md">
<q-layout
view="hHh Lpr fFf"
container
style="height: 600px; width: 100vw"
class="rounded-borders"
>
<L-Tile-Layer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
layer-type="base"
name="OpenStreetMap"
@click="updateMarker($event.latlng)"
></L-Tile-Layer>
<L-Marker :lat-lng="markerLatLng" @click="handleMarkerClick"></L-Marker>
<L-Routing-Machine
@routingstart="debugRoutingEvent"
@routesfound="debugRoutingEvent"
@routingerror="debugRoutingEvent"
:waypoints="waypoints"
/>
</L-Map>
<q-footer :class="$q.dark.isActive ? 'bg-primary' : 'bg-black'" style="height: 48px">
<q-toolbar>
<q-btn
class="q-mr-sm"
dense
flat
icon="menu"
round
size="sm"
@click="qLocDrawer = !qLocDrawer"
/>
<q-btn-dropdown flat label="Zoom To" size="sm" stretch>
<q-list>
<q-item v-close-popup v-ripple clickable @click="zoomTo('fmLoc')">
<q-item-section>
<q-item-label>Find My Location</q-item-label>
</q-item-section>
</q-item>
<q-item v-close-popup v-ripple clickable @click="zoomTo('simLoc')">
<q-item-section>
<q-item-label>Sim Location</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn label="Routing" @click="routeLayer = !routeLayer" size="sm" stretch />
</q-toolbar>
</q-footer>
<q-drawer
v-model="qLocDrawer"
show-if-above
mini-to-overlay
overlay
:width="300"
side="left"
:breakpoint="500"
:mini="miniState"
@mouseenter="miniState = false"
@mouseleave="miniState = true"
>
<q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: 0 }">
<q-list padding>
<q-item-label header>Location Queue</q-item-label>
<q-separator />
<LocationMark
v-for="key in locationQueueOrder"
:key="key"
:loc_id="key"
:active="locationQueueData[key].loc_id === currentLocation.loc_id"
:start="locationQueueData[key].start"
:address="locationQueueData[key].address"
:latitude="locationQueueData[key].latitude"
:longitude="locationQueueData[key].longitude"
:end="locationQueueData[key].end"
@item-clicked="zoomToCoods"
/>
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container>
<q-page>
<div style="height: 560px; width: 90vw; color: #000000">
<L-Map
ref="mapRef"
:center="center"
:zoom="zoom"
style="height: 550px; width: 100%"
@click="updateMarker"
@ready="onMapReady"
>
<L-Tile-Layer
layer-type="base"
name="OpenStreetMap"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
@click="updateMarker($event.latlng)"
></L-Tile-Layer>
<L-Layer-Group>
<L-Marker v-if="markerLatLng" :lat-lng="markerLatLng" @click="handleMarkerClick">
</L-Marker>
</L-Layer-Group>
<L-Layer-Group v-if="locationQueueOrder">
<L-Marker
v-for="locid in locationQueueOrder"
:key="locid"
:icon="getCustomIcon(locid)"
:lat-lng="[locationQueueData[locid].latitude, locationQueueData[locid].longitude]"
>
</L-Marker>
</L-Layer-Group>
<L-Layer-Group v-if="routeLayer">
<LRoutingMachine
v-bind="routingOptions"
@routingstart="debugRoutingEvent"
@routesfound="debugRoutingEvent"
@routingerror="debugRoutingEvent"
/>
</L-Layer-Group>
<L-Layer-Group v-if="findMyUpdate">
<L-Marker
v-if="findMyUpdate"
:icon="fmIcon"
:lat-lng="[findMyUpdate.latitude, findMyUpdate.longitude]"
></L-Marker>
<L-Circle
:fillOpacity="0.5"
:lat-lng="[findMyUpdate.latitude, findMyUpdate.longitude]"
:radius="findMyUpdate.horizontalAccuracy"
color="firebrick"
fillColor="indianred"
></L-Circle>
</L-Layer-Group>
</L-Map>
</div>
</q-page>
</q-page-container>
</q-layout>
</div>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import { useQuasar } from 'quasar';
import { ref } from 'vue';
import { computed, onMounted, reactive, ref } from 'vue';
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
import LRoutingMachine from 'components/LRoutingMachine.vue';
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
import { Icon, PinCirclePanel, PinStarPanel } from 'leaflet-extra-markers';
import 'leaflet-geosearch/dist/geosearch.css';
import 'leaflet/dist/leaflet.css';
import LRoutingMachine from 'components/LRoutingMachine.vue';
import LocationMark from 'components/LocationMark.vue';
import type { coords, SearchControlProps } from 'src/types';
import type { Map, LeafletMouseEvent } from 'leaflet';
import type { LeafletMouseEvent, Map } from 'leaflet';
import { storeToRefs } from 'pinia';
import { useSocketioStore } from 'stores/socketio';
import { useLeafletStore } from 'stores/leaflet';
import SetLocationDialog from 'components/SetLocationDialog.vue';
import { LMap, LMarker, LTileLayer } from '@vue-leaflet/vue-leaflet';
const waypoints = [
[ 38.7436056, -9.2304153 ],
[ 38.7436056, -0.131281 ],
];
import { LCircle, LLayerGroup, LMap, LMarker, LTileLayer } from '@vue-leaflet/vue-leaflet';
import { favorites } from 'constants/favorites';
const leafletStore = useLeafletStore();
const socketStore = useSocketioStore();
const { zoom, center, markerLatLng } = storeToRefs(socketStore);
const $q = useQuasar();
const mapRef = ref(null);
const responseMessage = ref('');
const { zoom, center, markerLatLng, qLocDrawer } = storeToRefs(leafletStore);
const debugRoutingEvent = (event) => {
console.log(`${event.type} event: `, event);
};
const socketStore = useSocketioStore();
const { currentLocation, nextLocation, locationQueueData, locationQueueOrder, findMyUpdate } =
storeToRefs(socketStore);
const $q = useQuasar();
const mapRef = ref();
const responseMessage = ref('');
const routeStart = ref(null);
const routeEnd = ref(null);
const routeLayer = ref(false);
const miniState = ref(true);
const onMapReady = (map: Map) => {
const provider = new OpenStreetMapProvider();
@@ -81,6 +185,48 @@ const onMapReady = (map: Map) => {
map.addControl(searchControl);
};
const fmIcon = new Icon({
color: 'indianred',
accentColor: 'firebrick',
content: 'FM',
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
});
const getCustomIcon = (locid: string) => {
const locationIndex = locationQueueOrder.value.indexOf(locid);
if (currentLocation.value && currentLocation.value.loc_id === locid) {
return new Icon({
color: 'pink',
accentColor: 'black',
content: '*',
contentColor: 'black',
scale: 1.5,
svg: PinStarPanel,
});
}
return new Icon({
color: 'blue',
accentColor: 'firebrick',
content: locationIndex.toString(),
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
});
};
const routingOptions = reactive({
waypoints: [
[40.910773020811, -73.891069806448],
[40.90930366920829, -73.87658695470259],
],
});
const debugRoutingEvent = (event) => {
console.log(`${event.type} event: `, event);
};
function updateMarker(event: LeafletMouseEvent) {
markerLatLng.value = [event.latlng.lat, event.latlng.lng];
center.value = [event.latlng.lat, event.latlng.lng];
@@ -114,10 +260,17 @@ function handleMarkerClick(event: LeafletMouseEvent) {
}
function setLocation(coords: coords, delay: number) {
let notType: string = 'positive';
try {
responseMessage.value = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
$q.notify({ type: 'positive', message: responseMessage.value });
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
if (setCmdRsp.sts === 'error') {
notType = 'negative';
}
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}`;
@@ -125,14 +278,65 @@ function setLocation(coords: coords, delay: number) {
console.error('Error setting location:', error);
responseMessage.value = `Failed to set location: Unknown error`;
}
$q.notify({ type: 'negative', message: responseMessage.value });
} finally {
$q.notify({ type: notType, message: responseMessage.value });
}
}
function zoomToCoods(arg: string) {
leafletStore.setCenter(
locationQueueData.value[arg].latitude,
locationQueueData.value[arg].longitude,
);
leafletStore.setZoom(50);
qLocDrawer.value = false;
}
function zoomTo(loc: string) {
switch (loc) {
case 'fmLoc':
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
}
$q.notify({ type: 'negative', message: 'Find My Location not available' });
break;
case 'simLoc':
if (
currentLocation.value &&
currentLocation.value.latitude &&
currentLocation.value.longitude
) {
leafletStore.setCenter(currentLocation.value.latitude, currentLocation.value.longitude);
}
$q.notify({ type: 'negative', message: 'Simulation Location not available' });
break;
case 'nextLoc':
if (nextLocation.value && nextLocation.value.latitude && nextLocation.value.longitude) {
leafletStore.setCenter(nextLocation.value.latitude, nextLocation.value.longitude);
}
$q.notify({ type: 'negative', message: 'Next Location not available' });
break;
default:
$q.notify({ type: 'negative', message: 'Invalid location' });
break;
}
}
onMounted(() => {
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
} else {
leafletStore.setCenter(favorites.home.coords.lat, favorites.home.coords.lng);
}
});
</script>
<style>
.l-map {
height: 100vh;
width: 100vw;
}
<style lang="sass">
.l-map
height: 100vh
width: 100vw
.q-item.q-router-link--active, .q-item--active
background-color: $accent
color: $primary
</style>