Files
mbmanager-dashboard/src/views/uikit/MapComponent.vue
T
kavehhn 8bae1d064a ADD: Utm Convert
FIX: Features data not saving and not loading
2025-05-10 20:48:03 +03:30

142 lines
3.9 KiB
Vue

<template>
<div class="map-container">
<!-- Search box -->
<div class="search-container">
<input v-model="searchQuery" @keyup.enter="handleSearch" placeholder="جستجو" class="search-input" />
</div>
<l-map ref="map" v-model:zoom="zoom" :center="center" :use-global-leaflet="false" @click="handleClick($event)">
<!-- Base layers -->
<l-control-layers position="topright" />
<!-- OpenStreetMap layer (default) -->
<l-tile-layer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" layer-type="base" name="نمای نقشه ای" :attribution="attribution" />
<!-- Satellite layer (optional) -->
<l-tile-layer
:visible="false"
url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
layer-type="base"
name="نمای ماهواره ای"
attribution="Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
/>
<!-- Marker -->
<l-marker v-if="marker.length > 0" :lat-lng="marker">
<l-popup> نقطه انتخاب شده </l-popup>
</l-marker>
</l-map>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
import 'leaflet/dist/leaflet.css';
import { LMap, LTileLayer, LMarker, LPopup, LControlLayers } from '@vue-leaflet/vue-leaflet';
import axios from 'axios';
// Props and emits
const props = defineProps({
modelValue: {
type: Array,
default: () => []
},
lon: {
type: Number
},
lat: {
type: Number
}
});
const emit = defineEmits(['update:modelValue']);
// Map configuration
const zoom = ref(12);
const center = ref([31.3183, 48.6706]);
const attribution = ref('Nilgoon Team');
const marker = ref([...props.modelValue]);
const map = ref(null);
// Search functionality
const searchQuery = ref('');
const searchByCoordinates = (lat, lon) => {
if (lat && lon) {
center.value = [parseFloat(lat), parseFloat(lon)];
zoom.value = 10;
marker.value = [parseFloat(lat), parseFloat(lon)];
emit('update:modelValue', marker.value);
}
};
defineExpose({
searchByCoordinates
});
const handleSearch = async () => {
if (!searchQuery.value) return;
try {
const response = await axios.get(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(searchQuery.value)}`);
if (response.data && response.data.length > 0) {
const { lat, lon } = response.data[0];
center.value = [parseFloat(lat), parseFloat(lon)];
zoom.value = 16;
marker.value = [parseFloat(lat), parseFloat(lon)];
emit('update:modelValue', marker.value);
}
} catch (error) {
console.error('Search failed:', error);
}
};
// Watch for changes in modelValue and sync with marker
watch(
() => props.modelValue,
(newValue) => {
marker.value = [...newValue];
},
{ immediate: true }
);
// Update marker and emit changes to modelValue
const handleClick = (event) => {
marker.value = [event.latlng.lat, event.latlng.lng];
emit('update:modelValue', marker.value);
};
</script>
<style scoped>
.map-container {
font-family: 'Estedad', sans-serif !important;
height: 500px;
width: 100%;
position: relative;
}
.leaflet-container {
font-family: 'Estedad', serif !important;
}
.search-container {
position: absolute;
top: 10px;
left: 10px;
z-index: 1000;
background: white;
padding: 5px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.search-input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
width: 250px;
font-family: 'Estedad', sans-serif;
}
</style>