route work
This commit is contained in:
@@ -37,12 +37,16 @@ type CommandAck = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
function setOpenedAppFab(fab: ControlCategoryKey) {
|
||||
function setOpenedAppFab(fab: ControlCategoryKey | null) {
|
||||
leafletStore.fabs.appControl.openedFab = fab;
|
||||
}
|
||||
|
||||
function handleOpenedAppFabUpdate(val: boolean, key: ControlCategoryKey) {
|
||||
if (val) setOpenedAppFab(key);
|
||||
if (val) {
|
||||
setOpenedAppFab(key);
|
||||
} else {
|
||||
setOpenedAppFab(null);
|
||||
}
|
||||
}
|
||||
|
||||
function formatUnknownError(commandLabel: string, error: unknown): NotificationResult {
|
||||
@@ -138,6 +142,23 @@ async function runRoutingCommand(cmdAttr: ControlAction): Promise<NotificationRe
|
||||
};
|
||||
}
|
||||
|
||||
if (cmdAttr.cmd === 'set_route_start_to_current_location') {
|
||||
if (simulationStore.currentLocation.loc_id) {
|
||||
const currentLocationData = simulationStore.getLocationData(simulationStore.currentLocation.loc_id);
|
||||
const result = leafletStore.setRouteStart(currentLocationData.latitude, currentLocationData.longitude);
|
||||
return {
|
||||
type: result.type,
|
||||
message: result.message || `${cmdAttr.name} requested`,
|
||||
};
|
||||
} else {
|
||||
const geoLocat = await leafletStore.getGeoLocationAsync()
|
||||
const result = leafletStore.setRouteStart(geoLocat.lat, geoLocat.lng);
|
||||
return {
|
||||
type: result.type,
|
||||
message: result.message || `${cmdAttr.name} requested`,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'negative',
|
||||
message: `Unsupported routing command: ${cmdAttr.cmd}`,
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { useLeafletStore } from 'stores/leaflet';
|
||||
import { LocateControl } from 'leaflet.locatecontrol';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
const leafletStore = useLeafletStore();
|
||||
|
||||
const locateControl = new LocateControl({
|
||||
position: 'topleft',
|
||||
flyTo: true,
|
||||
keepCurrentZoomLevel: true,
|
||||
returnToPrevBounds: true,
|
||||
layer: leafletStore.layerGroups.locateControl ?? undefined,
|
||||
});
|
||||
|
||||
const locationControlInit = ref(false);
|
||||
const locateControlActive = ref(false);
|
||||
const locateControlFollowing = ref(false);
|
||||
const locationFound = ref(false);
|
||||
const { locateControl } = storeToRefs(leafletStore);
|
||||
|
||||
const iconColor = computed(() =>
|
||||
locateControlActive.value
|
||||
? locationFound.value
|
||||
? locateControlFollowing.value
|
||||
locateControl.value.status.active
|
||||
? locationControl.value.status.Found
|
||||
? locateControl.value.status.Following
|
||||
? '#FC8428FF'
|
||||
: '#2074B6FF'
|
||||
: '#FFFFFF'
|
||||
@@ -29,7 +17,11 @@ const iconColor = computed(() =>
|
||||
);
|
||||
|
||||
const iconClass = computed(() => {
|
||||
if (locateControlActive.value && !locationFound.value && !locateControlFollowing.value) {
|
||||
if (
|
||||
locateControl.value.status.active &&
|
||||
!locateControl.value.status.found &&
|
||||
!locateControl.value.status.following
|
||||
) {
|
||||
return 'locate-control-icon-spinner';
|
||||
} else {
|
||||
return '';
|
||||
@@ -38,53 +30,18 @@ const iconClass = computed(() => {
|
||||
|
||||
const handleClick = () => {
|
||||
initialize();
|
||||
if (locateControlActive.value) {
|
||||
if (locateControl.value.status.active) {
|
||||
console.log('Stopping locate control');
|
||||
locateControl.stop();
|
||||
leafletStore.stopLocate();
|
||||
} else {
|
||||
console.log('Starting locate control');
|
||||
locateControl.start();
|
||||
leafletStore.startLocate();
|
||||
}
|
||||
};
|
||||
|
||||
function initialize() {
|
||||
if (!locationControlInit.value) {
|
||||
if (leafletStore.mapObject) {
|
||||
locationControlInit.value = true;
|
||||
leafletStore.mapObject.addControl(locateControl);
|
||||
|
||||
leafletStore.mapObject?.on('locateactivate', function () {
|
||||
console.log('Locate control activated');
|
||||
locateControlActive.value = true;
|
||||
});
|
||||
|
||||
leafletStore.mapObject?.on('locatedeactivate', function () {
|
||||
console.log('Locate control deactivated');
|
||||
locateControlActive.value = false;
|
||||
leafletStore.layerGroups.locateControl?.clearLayers();
|
||||
});
|
||||
|
||||
leafletStore.mapObject?.on('locationfound', function (e) {
|
||||
console.log('Location Found: ', e);
|
||||
console.log('Location found:', e.latlng);
|
||||
console.log('Accuracy:', e.accuracy, 'meters');
|
||||
locateControlFollowing.value = true;
|
||||
locationFound.value = true;
|
||||
});
|
||||
|
||||
leafletStore.mapObject?.on('moveend', function () {
|
||||
if (locateControlFollowing.value) {
|
||||
locateControlFollowing.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
leafletStore.mapObject?.on('locationtimeout', function (e) {
|
||||
const timeoutEvent = e as typeof e & { count?: number };
|
||||
console.log('Location timeout count:', timeoutEvent.count);
|
||||
locationFound.value = false;
|
||||
leafletStore.layerGroups.locateControl?.clearLayers();
|
||||
});
|
||||
}
|
||||
if (!locationControl.value.status.init) {
|
||||
leafletStore.initLocateControl();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ function zoomToCoords(arg: string) {
|
||||
"
|
||||
@item-clicked="zoomToCoords"
|
||||
@contextmenu.prevent="onDrawerContextMenu($event, key)"
|
||||
@touchstart.prevent="onDrawerContextMenu($event, key)"
|
||||
active-class="text-orange"
|
||||
/>
|
||||
</VueDraggable>
|
||||
|
||||
@@ -52,6 +52,7 @@ export async function useAddLocation(
|
||||
const simulationStore = useSimulationStore();
|
||||
const locationStore = useLocationStore();
|
||||
try {
|
||||
console.log ('address: %s, getRevGeocode: %s', address, getRevGeocode);
|
||||
const revGeo =
|
||||
!address && getRevGeocode
|
||||
/* ? await reverseGeocodeRateLimited(coords.lat, coords.lng) */
|
||||
|
||||
@@ -306,6 +306,16 @@ const baseControls = {
|
||||
iconColor: 'grey-10',
|
||||
isVisible: true,
|
||||
},
|
||||
set_route_start_to_current_location: {
|
||||
name: 'Set route start to current location',
|
||||
cmd: 'set_route_start_to_current_location',
|
||||
cmdClass: 'routing_cntrl_class',
|
||||
icon: 'mdi-navigation',
|
||||
cnfrm: false,
|
||||
disabled: false,
|
||||
iconColor: 'grey-10',
|
||||
isVisible: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies Record<ControlCategoryKey, ControlCategoryDefinition>;
|
||||
@@ -349,7 +359,8 @@ export function useControls() {
|
||||
return true;
|
||||
}),
|
||||
routing: computed(() => {
|
||||
return Boolean(leafletStore.routeSet.start.lng && leafletStore.routeSet.end.lng);
|
||||
return true;
|
||||
// return Boolean(leafletStore.routeSet.start.lng && leafletStore.routeSet.end.lng);
|
||||
}),
|
||||
} satisfies Record<ControlCategoryKey, ComputedRef<boolean>>;
|
||||
|
||||
|
||||
@@ -23,7 +23,13 @@ useMeta({
|
||||
|
||||
function layoutClickHandler(event: LeafletMouseEvent) {
|
||||
// if (!leafletStore.locationDrawerSettings.opened && !leafletStore.controlDrawerSettings.opened && !leafletStore.statusBarSettings.opened) {
|
||||
if (!leafletStore.locationDrawerSettings.opened && !leafletStore.fabs.statusBar) {
|
||||
if (
|
||||
!leafletStore.locationDrawerSettings.opened &&
|
||||
!leafletStore.fabs.statusBar.opened &&
|
||||
!leafletStore.fabs.layerControl.opened &&
|
||||
!leafletStore.fabs.favorites.opened &&
|
||||
!leafletStore.fabs.appControl.opened
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
@@ -33,9 +39,19 @@ function layoutClickHandler(event: LeafletMouseEvent) {
|
||||
) {
|
||||
leafletStore.locationsOpenedHandler(false);
|
||||
}
|
||||
if (!event.target.closest('#status-bar') && leafletStore.fabs.statusBar) {
|
||||
if (!event.target.closest('#status-bar') && leafletStore.fabs.statusBar.opened) {
|
||||
leafletStore.fabs.statusBar.opened = false;
|
||||
}
|
||||
if (!event.target.closest('#app-ctrl') && leafletStore.fabs.appControl.opened) {
|
||||
leafletStore.fabs.appControl.opened = false;
|
||||
}
|
||||
if (!event.target.closest('#favorite-ctrl') && leafletStore.fabs.favorites.opened) {
|
||||
leafletStore.fabs.favorites.opened = false;
|
||||
}
|
||||
if (!event.target.closest('#layer-ctrl') && leafletStore.fabs.layerControl.opened) {
|
||||
leafletStore.fabs.layerControl.opened = false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!event.target.closest('#control-drawer') && !leafletStore.controlDrawerSettings.pinned) {
|
||||
leafletStore.locationsOpenedHandler(false);
|
||||
|
||||
+121
-22
@@ -6,6 +6,7 @@ import * as L from 'leaflet';
|
||||
import type { Map, LatLngExpression, LayerGroup, FeatureGroup, Marker } from 'leaflet';
|
||||
import type { SearchResult } from 'components/models';
|
||||
import type { IRouter } from 'leaflet-routing-machine';
|
||||
import { LocateControl } from 'leaflet.locatecontrol';
|
||||
import { customRouter } from 'functions/serviceURL';
|
||||
import { startIcon, intermediateIcon, endIcon } from 'constants/icons';
|
||||
import type {
|
||||
@@ -66,7 +67,20 @@ interface RoutingOptions {
|
||||
createMarker: (i: number, waypoint: RoutingWaypoint, n: number) => L.Marker | false;
|
||||
}
|
||||
|
||||
interface State {
|
||||
interface LcStatus {
|
||||
active: boolean;
|
||||
found: boolean;
|
||||
following: boolean;
|
||||
init: boolean;
|
||||
}
|
||||
|
||||
interface LocateControlInstance {
|
||||
lc: ReturnType<typeof shallowRef<LocateControl | null>>;
|
||||
status: LcStatus;
|
||||
latLng: L.LatLng | null;
|
||||
}
|
||||
|
||||
interface StoreState {
|
||||
zoom: number;
|
||||
center: [number, number] | [null, null] | null;
|
||||
mapObject: ReturnType<typeof shallowRef<Map | null>>;
|
||||
@@ -85,6 +99,7 @@ interface State {
|
||||
};
|
||||
layerControl: LayerControl;
|
||||
layerGroups: LayerGroups;
|
||||
locateControl: LocateControlInstance;
|
||||
routeSet: {
|
||||
start: LatLng;
|
||||
end: LatLng;
|
||||
@@ -105,7 +120,7 @@ interface State {
|
||||
}
|
||||
|
||||
export const useLeafletStore = defineStore('leafletStore', {
|
||||
state: (): State => {
|
||||
state: (): StoreState => {
|
||||
return {
|
||||
zoom: 10,
|
||||
center: [favorites.home.coords.lat, favorites.home.coords.lng],
|
||||
@@ -128,6 +143,16 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
findMy: shallowRef(null),
|
||||
locateControl: shallowRef(null),
|
||||
},
|
||||
locateControl: {
|
||||
lc: shallowRef(null),
|
||||
status: {
|
||||
active: false,
|
||||
following: false,
|
||||
init: false,
|
||||
found: false,
|
||||
},
|
||||
latLng: null as L.LatLng | null,
|
||||
},
|
||||
leafletDrawerOpen: false,
|
||||
locationDrawerSettings: {
|
||||
opened: false,
|
||||
@@ -171,45 +196,48 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
value: 1,
|
||||
label: 'Open Street Map',
|
||||
layer: shallowRef(
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© OpenStreetMap',
|
||||
minZoom: 2,
|
||||
noWrap: true,
|
||||
}
|
||||
))
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: 'Topography',
|
||||
layer: shallowRef(L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
|
||||
layer: shallowRef(
|
||||
L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
|
||||
minZoom: 2,
|
||||
maxZoom: 17,
|
||||
attribution: '© OpenTopoMap',
|
||||
noWrap: true,
|
||||
}))
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: 'Satellite',
|
||||
layer: shallowRef(L.tileLayer(
|
||||
layer: shallowRef(
|
||||
L.tileLayer(
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||
{
|
||||
minZoom: 2,
|
||||
maxZoom: 19,
|
||||
attribution: '© ArcGIS',
|
||||
noWrap: true,
|
||||
}))
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
baseLayerWMS: {
|
||||
selected: false,
|
||||
label: 'OpenStreetMap Transparent',
|
||||
layer: shallowRef(L.tileLayer.wms(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{
|
||||
layer: shallowRef(
|
||||
L.tileLayer.wms('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
minZoom: 2,
|
||||
maxZoom: 19,
|
||||
attribution: '© OpenStreetMap',
|
||||
@@ -217,8 +245,8 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
transparent: true,
|
||||
format: 'image/png',
|
||||
opacity: 0.5,
|
||||
}
|
||||
)),
|
||||
}),
|
||||
),
|
||||
},
|
||||
routingOptions: {
|
||||
waypoints: [],
|
||||
@@ -259,6 +287,61 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
setMap(map: Map) {
|
||||
this.mapObject = map;
|
||||
},
|
||||
initLocateControl() {
|
||||
const lc = new LocateControl({
|
||||
position: 'topleft',
|
||||
flyTo: true,
|
||||
keepCurrentZoomLevel: true,
|
||||
returnToPrevBounds: true,
|
||||
layer: this.layerGroups.locateControl ?? undefined,
|
||||
});
|
||||
this.locateControl.lc = lc;
|
||||
this.locateControl.status.init = true;
|
||||
if (this.mapObject) {
|
||||
this.mapObject.addControl(lc);
|
||||
this.mapObject.on('locationerror', () => {
|
||||
this.locateControl.latLng = null;
|
||||
});
|
||||
this.mapObject.on('locateactivate', () => {
|
||||
console.log('Locate control activated');
|
||||
this.locateControl.status.active = true;
|
||||
});
|
||||
this.mapObject.on('locatedeactivate', () => {
|
||||
console.log('Locate control deactivated');
|
||||
this.locateControl.status.active = false;
|
||||
this.layerGroups.locateControl?.clearLayers();
|
||||
});
|
||||
this.mapObject.on('locationfound', (e) => {
|
||||
console.log('Location Found: ', e);
|
||||
console.log('Location found:', e.latlng);
|
||||
console.log('Accuracy:', e.accuracy, 'meters');
|
||||
this.locateControl.latLng = e.latlng;
|
||||
this.locateControl.status.following = true;
|
||||
this.locateControl.status.found = true;
|
||||
});
|
||||
this.mapObject.on('moveend', () => {
|
||||
if (this.locateControl.status.following) {
|
||||
this.locateControl.status.following = false;
|
||||
}
|
||||
});
|
||||
this.mapObject.on('locationtimeout', (e) => {
|
||||
const timeoutEvent = e as typeof e & { count?: number };
|
||||
console.log('Location timeout count:', timeoutEvent.count);
|
||||
this.locateControl.status.found = false;
|
||||
this.layerGroups.locateControl?.clearLayers();
|
||||
});
|
||||
}
|
||||
},
|
||||
startLocate() {
|
||||
if (this.locateControl.lc) {
|
||||
this.locateControl.lc.start();
|
||||
}
|
||||
},
|
||||
stopLocate() {
|
||||
if (this.locateControl.lc) {
|
||||
this.locateControl.lc.stop();
|
||||
}
|
||||
},
|
||||
/*
|
||||
setLayerGroup(layerGroup: LayerGroup, name: string)
|
||||
this.layerGroups[name] = layerGroup;
|
||||
@@ -293,23 +376,23 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
this.zoom = zoom;
|
||||
},
|
||||
zoomIn() {
|
||||
this.mapObject?.zoomIn()
|
||||
this.mapObject?.zoomIn();
|
||||
},
|
||||
zoomOut() {
|
||||
this.mapObject?.zoomOut()
|
||||
this.mapObject?.zoomOut();
|
||||
},
|
||||
setBaseLayer(newVal?: number, oldVal?: number) {
|
||||
if (newVal === undefined && this.baseLayer.selected === undefined) return;
|
||||
if (oldVal && this.mapObject) {
|
||||
const oldLayer = this.baseLayer.options.filter(u => u.value === oldVal)[0];
|
||||
const oldLayer = this.baseLayer.options.filter((u) => u.value === oldVal)[0];
|
||||
if (oldLayer) {
|
||||
console.log("OldLayer name: ", oldLayer.label);
|
||||
console.log('OldLayer name: ', oldLayer.label);
|
||||
oldLayer.layer!.remove();
|
||||
}
|
||||
}
|
||||
const bLayer = this.baseLayer.options.filter(u => u.value === this.baseLayer.selected)[0];
|
||||
const bLayer = this.baseLayer.options.filter((u) => u.value === this.baseLayer.selected)[0];
|
||||
if (this.mapObject && bLayer) {
|
||||
console.log("NewLayer name: ", bLayer.label);
|
||||
console.log('NewLayer name: ', bLayer.label);
|
||||
bLayer.layer!.addTo(this.mapObject);
|
||||
}
|
||||
},
|
||||
@@ -422,6 +505,22 @@ export const useLeafletStore = defineStore('leafletStore', {
|
||||
}
|
||||
return { type: result.notificationType, message: result.responseMessage };
|
||||
},
|
||||
setRouteStart(lat: number, lng: number) {
|
||||
this.layerControl.routing = true;
|
||||
this.routeSet.start = { lat: lat, lng: lng };
|
||||
return { type: 'positive', message: 'Route start set.' };
|
||||
},
|
||||
getGeoLocationAsync() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.locateControl?.lc?.start();
|
||||
this.mapObject?.once('locationfound', function (e) {
|
||||
resolve(e.latlng);
|
||||
});
|
||||
this.mapObject?.once('locationerror', function (e) {
|
||||
reject(new Error(e.message));
|
||||
});
|
||||
});
|
||||
},
|
||||
clearRoute() {
|
||||
this.layerControl.routing = false;
|
||||
this.clearRouteSegments();
|
||||
|
||||
Reference in New Issue
Block a user