Initialize project: set up Quasar framework, configured essential tools (ESLint, Prettier, EditorConfig), integrated Vue Router and Axios, added Leaflet-based map with custom components, and defined project dependencies and configs.
This commit is contained in:
201
src/components/LeafletTest.vue
Normal file
201
src/components/LeafletTest.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div style="height:600px; width:800px">
|
||||
<q-toolbar class="bg-primary text-white q-my-md shadow-2">
|
||||
<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>
|
||||
<l-map @ready="onMapReady" ref="mapRef" :zoom="zoom" :center="center" style="height: 500px; width: 100%;" @click="updateMarker">
|
||||
<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-map>
|
||||
<StatusBar />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuasar } from "quasar";
|
||||
import { Ref, ref } from "vue";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { LMap, LTileLayer, LMarker } from "@vue-leaflet/vue-leaflet";
|
||||
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
||||
import "leaflet-geosearch/dist/geosearch.css";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import type { Map, LeafletMouseEvent } from 'leaflet';
|
||||
import SetLocationDialog from "components/SetLocationDialog.vue";
|
||||
import StatusBar from "components/StatusBar.vue"
|
||||
import { api } from "src/boot/axios";
|
||||
|
||||
const $q = useQuasar();
|
||||
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("");
|
||||
|
||||
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 provider = new OpenStreetMapProvider();
|
||||
const searchOptions: SearchControlProps = {
|
||||
provider: provider,
|
||||
showMarker: false,
|
||||
autoClose: true,
|
||||
updateMap: true,
|
||||
showPopup: true,
|
||||
style: 'bar',
|
||||
acceptAutoLoad: true,
|
||||
autoComplete: true,
|
||||
autoCompleteDelay: 250,
|
||||
retainZoomLevel: false,
|
||||
animateZoom: true,
|
||||
keepResult: true
|
||||
};
|
||||
|
||||
const searchControl = new GeoSearchControl(searchOptions);
|
||||
map.addControl(searchControl);
|
||||
};
|
||||
|
||||
function updateMarker(event: LeafletMouseEvent) {
|
||||
markerLatLng.value = [event.latlng.lat, event.latlng.lng];
|
||||
center.value = [event.latlng.lat, event.latlng.lng];
|
||||
}
|
||||
|
||||
function handleMarkerClick(event: LeafletMouseEvent) {
|
||||
$q.dialog({
|
||||
component: SetLocationDialog,
|
||||
componentProps: {
|
||||
lat: event.latlng.lat,
|
||||
lng: event.latlng.lng
|
||||
}
|
||||
}).onOk(() => {
|
||||
void setLocation({ lat: event.latlng.lat, lng: event.latlng.lng });
|
||||
console.log("Dialog confirmed");
|
||||
}).onCancel(() => {
|
||||
console.log("Dialog cancelled");
|
||||
}).onDismiss(() => {
|
||||
console.log("Dialog dismissed");
|
||||
});
|
||||
}
|
||||
|
||||
function handleFavClick(coords: coords) {
|
||||
center.value = [coords.lat, coords.lng];
|
||||
markerLatLng.value = [coords.lat, coords.lng];
|
||||
}
|
||||
|
||||
async function setLocation(coords: coords) {
|
||||
try {
|
||||
const payLoadData = {
|
||||
latitude: coords.lat,
|
||||
longitude: coords.lng
|
||||
};
|
||||
const { data } = await api({
|
||||
method: "post",
|
||||
url: "/set",
|
||||
data: payLoadData
|
||||
});
|
||||
console.log("Location set successfully:", data.data);
|
||||
responseMessage.value = `Location successfully set! New location: ${data.lat}, ${data.lng}`;
|
||||
$q.notify({ type: 'positive', message: responseMessage.value });
|
||||
} catch (error: unknown) {
|
||||
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`;
|
||||
}
|
||||
$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>
|
||||
|
||||
<style>
|
||||
.l-map {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user