142 lines
3.9 KiB
Vue
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 © Esri — 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>
|