import { tools } from '@store/Modules/tools' import { useQuasar } from 'quasar' import { defineComponent, onMounted, onBeforeUnmount, ref, watch, computed, PropType, nextTick, shallowRef } from 'vue' import 'leaflet/dist/leaflet.css' import * as L from 'leaflet' import 'leaflet.markercluster/dist/MarkerCluster.css' import 'leaflet.markercluster/dist/MarkerCluster.Default.css' import 'leaflet.markercluster' import '../../utils/leaflet-extensions'; // Importa le estensioni import { useUserStore } from '@src/store/UserStore' // Importa le immagini dei marker import icon from 'leaflet/dist/images/marker-icon.png' import iconShadow from 'leaflet/dist/images/marker-shadow.png' import { ICoordGPS, ICoordLatLng } from '@src/model' export default defineComponent({ name: 'CMapEditAddressByCoord', props: { modelValue: { type: Object as PropType, required: true, }, editaddress: { type: Boolean, required: true, }, visuMappa: { type: Boolean, required: false, default: true, } }, setup(props, { emit }) { const $q = useQuasar() const userStore = useUserStore() const mapContainer = ref(null); const iconWidth = ref(25) const iconHeight = ref(41) const map = shallowRef(null) const marker = ref(null) const suggestions = ref([]); const isMapDialogOpen = ref(false) const mostraMappa = ref(true) const localAddress = ref(props.modelValue.address); const localAddressObj = ref({ label: '', value: '' }); const localCoordinates = ref({ lat: props.modelValue.coordinates[1], lng: props.modelValue.coordinates[0] }); const modificato = ref(false) const fineLoad = ref(false) const zoomLevel = ref(17) const updateAll = () => { if (localAddress.value) emit('update:modelValue', { address: localAddress.value, type: 'Point', coordinates: [localCoordinates.value.lng, localCoordinates.value.lat] } as ICoordGPS); }; // Funzione per aggiornare il nome const updateAddress = () => { if (localAddress.value) updateAll() }; // Funzione per aggiornare il cognome const updateCoordinates = () => { updateAll() }; // Monitoraggio delle modifiche alle props watch(() => props.modelValue.address, (newValue) => { localAddress.value = newValue; }); watch(() => props.modelValue.coordinates, (newValue) => { localCoordinates.value.lat = newValue[1]; localCoordinates.value.lng = newValue[0]; }); watch(() => localCoordinates.value.lat, (newValue) => { if (fineLoad.value) { modificato.value = true } updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng); }); watch(() => localCoordinates.value.lng, (newValue) => { if (fineLoad.value) { modificato.value = true } updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng); }); const myheight = computed(() => { return $q.screen.height - 150 }) // Funzione per ottenere e stampare il livello di zoom function getZoomLevel() { zoomLevel.value = map.value ? map.value.getZoom() : 17; // console.log('Current zoom level:', zoomLevel); } const initMap = () => { // Configura l'icona di default const DefaultIcon = L.icon({ iconUrl: icon, shadowUrl: iconShadow, iconSize: [iconWidth.value, iconHeight.value], iconAnchor: [iconWidth.value / 2, iconHeight.value], popupAnchor: [1, -iconHeight.value], shadowSize: [iconHeight.value, iconHeight.value] }) L.Marker.prototype.options.icon = DefaultIcon zoomLevel.value = 17 map.value = L.map(mapContainer.value, { zoomControl: true, zoom: zoomLevel.value, zoomAnimation: true, fadeAnimation: true, markerZoomAnimation: true, center: [42.71, 12.934], } ) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map.value) getZoomLevel(); // Ottenere il livello di zoom quando la mappa viene ridimensionata map.value.on('zoomend', getZoomLevel); /* const closeButton = L.control({ position: 'topright' }); closeButton.onAdd = function () { const button = L.DomUtil.create('button', 'leaflet-control-button'); button.innerHTML = 'Chiudi'; // Testo del pulsante button.style.backgroundColor = 'red'; button.style.color = 'white'; button.style.border = 'none'; button.style.borderRadius = '5px'; button.style.padding = '10px'; button.style.cursor = 'pointer'; button.onclick = () => { mostraMappa.value = false; // Chiudi il dialog della mappa }; return button; }; closeButton.addTo(map.value); */ } const onResize = () => { if (map.value) { map.value.invalidateSize(); } }; const updateMarker = (lat: number, lng: number) => { // console.log('aggiorna marker', lat, lng) if (fineLoad.value) { modificato.value = true } if (marker.value) { marker.value.setLatLng([lat, lng]) } else { marker.value = L.marker([lat, lng], { draggable: true }).addTo(map.value!) marker.value.on('dragend', (event: L.LeafletEvent) => { const position = (event.target as L.Marker).getLatLng() localCoordinates.value = { lat: parseFloat(position.lat.toFixed(6)), lng: parseFloat(position.lng.toFixed(6)), }; if (fineLoad.value) { mostraMappa.value = true } getAddressFromCoordinates(localCoordinates.value.lat, localCoordinates.value.lng); // updateCoordinates() }) } map.value?.setView([lat, lng], zoomLevel.value) } function updateMap() { map.value?.setView([localCoordinates.value.lat, localCoordinates.value.lng], zoomLevel.value) } const searchAddress = async () => { try { const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(localAddress.value)}`) const data = await response.json() if (data && data.length > 0) { localCoordinates.value = { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) } localAddress.value = data[0].display_name if (fineLoad.value) { mostraMappa.value = true } isMapDialogOpen.value = true } } catch (error) { console.error('Error searching address:', error) } } const getAddressSuggestions = async (val: string, update: Function) => { try { if (val.length === 0) { suggestions.value = []; update(); return; } const response = await fetch( `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(val)}` ); const data = await response.json(); suggestions.value = data.map((item: any) => ({ label: item.display_name, value: item.display_name, lat: item.lat, lon: item.lon })); update(); } catch (error) { console.error('Error fetching address suggestions:', error); } }; const getAddressFromCoordinates = async (lat: number, lon: number) => { const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`; try { const response = await fetch(url); if (!response.ok) { throw new Error('Errore nella richiesta di geocoding'); } const data = await response.json(); localAddress.value = data.display_name; // Ottieni l'indirizzo localAddressObj.value = { label: localAddress.value, value: localAddress.value } } catch (error) { console.error('Errore durante il geocoding:', error); localAddress.value = ''; // In caso di errore, resetta l'indirizzo localAddressObj.value = { label: '', value: '' } } }; watch(localAddressObj, (newAddress: any) => { if (newAddress) { const match: any = suggestions.value.find((suggestion: any) => suggestion.value === newAddress.value); if (match && match.lat) { localAddress.value = match.value; localCoordinates.value = { lat: parseFloat(parseFloat(match.lat).toFixed(6)), lng: parseFloat(parseFloat(match.lon).toFixed(6)), }; updateCoordinates() updateAddress() updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); } } }); function salvaCoordinate() { updateCoordinates() updateAddress() $q.notify({ type: 'positive', message: 'Coordinate modificate, Salvare per rendere effettiva la modifica', position: 'bottom', timeout: 2000 }) modificato.value = false mostraMappa.value = false } onMounted(() => { if (!props.modelValue.address) { localAddress.value = '' localAddressObj.value = { label: '', value: '' } } else { localAddressObj.value = { label: props.modelValue.address, value: props.modelAddress } } if (!props.modelValue.coordinates) { localCoordinates.value = { lat: 0, lng: 0 } } initMap() updateMap() updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); if (!localCoordinates.value || !localCoordinates.value.lat) { mostraMappa.value = false } fineLoad.value = true window.addEventListener('resize', onResize); nextTick(() => { mostraMappa.value = props.visuMappa }) }) onBeforeUnmount(() => { window.removeEventListener('resize', onResize); }); const getCurrentLocation = () => { if ('geolocation' in navigator) { navigator.geolocation.getCurrentPosition( (position) => { localCoordinates.value = { lat: parseFloat(position.coords.latitude.toFixed(6)), lng: parseFloat(position.coords.longitude.toFixed(6)), }; if (fineLoad.value) { mostraMappa.value = true; } updateCoordinates(); updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); }, (error) => { console.error('Error getting location:', error); $q.notify({ type: 'negative', message: 'Errore durante il rilevamento della posizione.', }); } ); } else { $q.notify({ type: 'negative', message: 'Geolocalizzazione non supportata dal browser.', }); } }; function annullaSalvataggio() { localCoordinates.value.lng = props.modelValue.coordinates[0] localCoordinates.value.lat = props.modelValue.coordinates[1] localAddress.value = props.modelValue.address updateMarker(localCoordinates.value.lat, localCoordinates.value.lng); mostraMappa.value = false modificato.value = false } // evento dopo il mounting return { searchAddress, myheight, isMapDialogOpen, suggestions, getAddressSuggestions, localAddress, localCoordinates, updateAddress, updateCoordinates, mostraMappa, localAddressObj, getCurrentLocation, salvaCoordinate, modificato, annullaSalvataggio, mapContainer, fineLoad, } } })