import { tools } from '@store/Modules/tools' import { useQuasar } from 'quasar' import { PropType, defineComponent, onMounted, ref, toRaw, computed, toRef, watch, shallowRef } from 'vue' import 'leaflet/dist/leaflet.css' // @ts-ignore import * as L from 'leaflet' import '../../utils/leaflet-extensions'; // Importa le estensioni import 'leaflet.markercluster/dist/MarkerCluster.css' import 'leaflet.markercluster/dist/MarkerCluster.Default.css' import 'leaflet.markercluster' import { useUserStore } from '@src/store/UserStore' import { useGlobalStore } from '@src/store/globalStore' import { useI18n } from '@src/boot/i18n' import { ICoordGPS } from '@src/model' export default defineComponent({ name: 'CMapByTable', emits: ['clickMarker', 'updateMapBoundaries', 'updateMapZoomOut'], props: { mytable: { type: String, required: true, }, arrcord: { type: Array as PropType, required: false, default: () => { return [] } } }, setup(props, { emit }) { const $q = useQuasar() const { t } = useI18n() const userStore = useUserStore() const globalStore = useGlobalStore() const iconWidth = ref(25) const iconHeight = ref(40) const zoom = ref(8) const map = shallowRef(null); const visiblePosition = ref(false) const markers = shallowRef(null); const isTrackingLocation = ref(false) const debug = ref(tools.isDevelop()) const currentMarkerPositionGPS = shallowRef(null) const centerCoordinates = ref<{ lat: number; lng: number }>({ lat: 0, lng: 0 }); // const arrMarkers = ref([]) const recordShowed = ref(null) const markerShowed = shallowRef(null) const markerTemporaneo = shallowRef(null) const mapOptions = ref({ zoomControl: false, zoomAnimation: false, fadeAnimation: true, markerZoomAnimation: true, }) const tileLayerOptions = { maxZoom: 17, minZoom: 3, } const myIcon = L.icon({ iconUrl: 'images/icon.png', iconSize: [30, 30], iconAnchor: [22, 35], popupAnchor: [-6, -36], shadowUrl: 'images/marker-shadow.png', shadowSize: [60, 30], shadowAnchor: [22, 35] }); const myIconPosAtt = L.icon({ iconUrl: 'images/icon.png', iconSize: [30, 30], iconAnchor: [22, 35], popupAnchor: [-6, -36], shadowUrl: 'images/marker-shadow.png', shadowSize: [60, 30], shadowAnchor: [22, 35] }); const iconPosition = L.divIcon({ className: 'custom-marker', // Classe CSS personalizzata html: 'location_on', iconSize: [40, 40], iconAnchor: [22, 35], popupAnchor: [-6, -36], }); const currentLocationIcon = L.divIcon({ className: 'current-location-icon', iconSize: [20, 20], iconAnchor: [10, 10] }); const arrcord = toRef(props, 'arrcord') const precZoomLevel = ref(0) const debounceTimer = ref(null) watch(() => visiblePosition.value, () => { if (visiblePosition.value === true) { getCurrentPosition() } else { removeCurrentMarker() } }) function mywidth() { return tools.getwidth($q) - 20 } function myheight() { return $q.screen.height - 220 } const iconUrl = computed(() => { return `https://placekitten.com/${iconWidth.value}/${iconHeight.value}`; }) const iconSize = computed(() => { return [iconWidth.value, iconHeight.value]; }) function changeIcon() { iconWidth.value += 2; if (iconWidth.value > iconHeight.value) { iconWidth.value = Math.floor(iconHeight.value / 2); } } function getColor(d: any) { return d > 1000 ? '#800026' : d > 500 ? '#BD0026' : d > 200 ? '#E31A1C' : d > 100 ? '#FC4E2A' : d > 50 ? '#FD8D3C' : d > 20 ? '#FEB24C' : d > 10 ? '#FED976' : '#FFEDA0'; } function style(feature: any) { return { fillColor: getColor(feature.properties.density), weight: 2, opacity: 1, color: 'white', dashArray: '3', fillOpacity: 0.7 }; } watch(arrcord, () => { updateMap() }) onMounted(async () => { initMap() }); function log(str: string) { console.log(str) } function getCoordinates(e: any) { // Ottieni la latitudine e la longitudine dal click const lat = e.latlng.lat const lng = e.latlng.lng // Fai qualcosa con le coordinate, ad esempio stamparle in console // console.log(`Latitudine: ${lat}, Longitudine: ${lng}`) } function getIconName(myrec: any) { const myarrSectors = myrec.sector if (!myarrSectors) return 'mdi-map-marker-outline' let sectId = myarrSectors[0]._id return globalStore.getIconBySector(sectId) } function updateBoundaries(updatedata: boolean) { if (map.value) { // Get the boubdaries of the map showed const bounds = map.value.getBounds(); // tojson tools.setCookie(tools.COOK_MAPBOUNDS + 'ne', tools.objToStr(bounds.getNorthEast())) tools.setCookie(tools.COOK_MAPBOUNDS + 'sw', tools.objToStr(bounds.getSouthWest())) // Update Map Boundaries to the Parent emit('updateMapBoundaries', bounds.getNorthEast(), bounds.getSouthWest(), updatedata); } } function updateMapZoomOut() { emit('updateMapZoomOut', map.value.getZoom()); } /** * Updates the center coordinates and zoom level of the map, and saves them in cookies. * * @return {void} This function does not return a value. */ function onMoveEnd() { const center = map.value.getCenter(); // Ottieni le coordinate centrali centerCoordinates.value = { lat: center.lat, lng: center.lng }; // Salva le coordinate const currentZoomLevel = map.value.getZoom(); tools.setCookie('last_lat', center.lat) tools.setCookie('last_lng', center.lng) tools.setCookie('zoom', currentZoomLevel) updateBoundaries(true) precZoomLevel.value = map.value.getZoom(); } const onZoomEvent = () => { // Annulla il timer precedente se presente if (debounceTimer.value) { clearTimeout(debounceTimer.value); } // Inizia un nuovo timer di 1 secondo debounceTimer.value = setTimeout(() => { const currentZoomLevel = map.value.getZoom(); if (currentZoomLevel < precZoomLevel.value) { // Aggiorna i dati della mappa updateMapZoomOut(); // Aggiorna il livello di zoom precedente precZoomLevel.value = currentZoomLevel; } }, 500); } const onCustomButtonClick = () => { alert("Pulsante personalizzato cliccato!"); // Logica aggiuntiva qui }; function initMap() { if (true) { const getLastCoord = [tools.getCookie('last_lat', 42.71), tools.getCookie('last_lng', 12.934)] zoom.value = tools.getCookie('zoom', 8, true) // console.log('getLastCoord', getLastCoord, 'zoom', zoom.value) const newmapopt = { ...mapOptions.value, zoom: zoom.value, center: getLastCoord } map.value = L.map('map', newmapopt); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', tileLayerOptions) .addTo(map.value); // Aggiunta dei controlli di zoom const zoomControl = L.control.zoom({ position: "topright", }).addTo(map.value); // Aggiunta di un pulsante personalizzato // @ts-ignore const customButton = L.control({ position: "topright" }); customButton.onAdd = function () { const button = L.DomUtil.create("button", "custom-zoom-button"); button.innerHTML = t('grid.showlist'); // Testo del pulsante button.onclick = onCustomButtonClick; // Gestore evento click return button; }; // customButton.addTo(map.value); map.value.on('moveend', () => { onMoveEnd() }); map.value.on("zoomend", onZoomEvent); // @ts-ignore markers.value = L.markerClusterGroup(); map.value.addLayer(markers.value); // Assicuriamoci che la mappa sia completamente caricata prima di procedere map.value.whenReady(() => { // console.log('Mappa inizializzata e pronta'); updateMap(); precZoomLevel.value = map.value.getZoom() }); } } function createSingleMarkerByCoordinates(rec: any) { const markerHtml = `
Shadow
`; const markerIcon = L.divIcon({ className: 'custom-marker', // Classe CSS personalizzata html: markerHtml, iconSize: [40, 40], iconAnchor: [22, 35], popupAnchor: [-6, -36], shadowUrl: 'images/marker-shadow.png', shadowSize: [60, 30], shadowAnchor: [22, 35] }); // @ts-ignore let each_marker = new L.marker( [rec.coordinate_gps.coordinates[1], rec.coordinate_gps.coordinates[0]], { icon: markerIcon } ) .bindPopup(() => { let container = L.DomUtil.create('div'); let strHTML = `${rec.descr}` if (debug.value) { // strHTML += `
Lat: ${rec.coordinate_gps.coordinates[1]}
Lng: ${rec.coordinate_gps.coordinates[0]}`; } container.innerHTML = strHTML let fakeLink: any = container.querySelector('.fake-link'); L.DomEvent.on(fakeLink, 'click', (e) => { L.DomEvent.stopPropagation(e); ApriScheda(rec._id); each_marker.closePopup(); }); return container; }, { closeButton: false }) // Rimuove il pulsante di chiusura dal popup .on('click', () => { if (!$q.screen.lt.sm) { markerClick(rec._id) } }) .on('mouseover', () => { if (!$q.screen.lt.sm) { each_marker.openPopup() } }) .on('mouseout', () => { if (!$q.screen.lt.sm) { each_marker.closePopup() } }); // Salva l'ID del mio record, per poi poterlo trovare each_marker.mytable = props.mytable each_marker.idRec = rec._id // Aggiungi il marker all'array in memoria arrMarkers.value.push(each_marker) return each_marker } function updateMap() { if (!map.value || !markers.value) return; if (map.value) { // console.log('updateMap') markers.value.clearLayers() arrMarkers.value = [] for (const rec of arrcord.value) { if (rec.coordinate_gps.coordinates) { const each_marker = createSingleMarkerByCoordinates(rec) markers.value.addLayer(each_marker); } } // Aggiungi il gruppo di marker cluster alla mappa map.value.addLayer(markers.value); // console.log('markerShowed', markerShowed.value) if (markerShowed.value) { markerShowed.value.closePopup() const trovatomarker = arrMarkers.value.find((marker: any) => markerShowed.value && (marker.idRec === markerShowed.value.idRec)) if (!trovatomarker) { // non presente, quindi lo aggiunge markers.value.addLayer(markerShowed.value); } else { markerShowed.value = trovatomarker } markerShowed.value.openPopup(); // Mostra il popup } if (visiblePosition.value && currentMarkerPositionGPS.value) { // Aggiungi un marker per la posizione attuale, se desiderato /*const tempmark = L.marker( [currentMarkerPositionGPS.value.getLatLng().lat, currentMarkerPositionGPS.value.getLatLng().lng], { icon: currentLocationIcon } ).addTo(map.value) .bindPopup('Posizione attuale') // .openPopup(); currentMarkerPositionGPS.value = tempmark*/ markers.value.addLayer(currentMarkerPositionGPS.value); } updateBoundaries(false) } } function markerClick(id: any) { emit('clickMarker', id) // emit('clickMarker', id) } function ApriScheda(id: any) { emit('clickMarker', id) } function gotoCurrentLocation() { getCurrentPosition(); } function flyToCoord(lat: number, lng: number, callback: () => void) { try { map.value.off('moveend', callback) if (map.value.getZoom() < 13) { zoom.value = 13; } else { zoom.value = map.value.getZoom() } // Centra la mappa sulla posizione attuale map.value.flyTo([lat, lng], zoom.value, { animate: true, duration: 0.7 }) // Usa l'evento 'moveend' per sapere quando l'animazione รจ completata map.value.on('moveend', callback); } catch (error) { } } const getCurrentPosition = () => { if (navigator.geolocation) { isTrackingLocation.value = true; // Setta lo stato a "in tracciamento" navigator.geolocation.getCurrentPosition( position => { const lat = position.coords.latitude const lng = position.coords.longitude flyToCoord(lat, lng, () => { if (currentMarkerPositionGPS.value) { map.value.removeLayer(currentMarkerPositionGPS.value) } // Aggiungi un marker per la posizione attuale, se desiderato currentMarkerPositionGPS.value = L.marker( [lat, lng], { icon: currentLocationIcon } ).addTo(map.value) .bindPopup('Posizione attuale') // .openPopup(); isTrackingLocation.value = false; // Resetta lo stato di tracciamento }) }, error => { console.error('Errore nel recupero della posizione:', error); isTrackingLocation.value = false; // Resetta lo stato di tracciamento } ); } else { console.error('Geolocalizzazione non supportata dal browser.'); } } const removeCurrentMarker = () => { if (currentMarkerPositionGPS.value) { map.value.removeLayer(currentMarkerPositionGPS.value); // Rimuovi il marker dalla mappa currentMarkerPositionGPS.value = null; // Resetta il riferimento } } function findMarkerByIdRec(id: any) { const marker = arrMarkers.value.find((marker: any) => { return marker.idRec === id; }); return marker; } function showInMap(rec: any) { // console.log('showInMap', rec) // Find if is already in the map let existingMarker = findMarkerByIdRec(rec._id) if (!existingMarker) { if (markerTemporaneo.value) { // Rimuovo il marker temporaneo usato in precedenza map.value.removeLayer(markerTemporaneo.value) markerTemporaneo.value = null } // Se non la trovo nella mappa, allora inserisco un nuovo marker temporaneo e lo aggiungo alla mappa existingMarker = createSingleMarkerByCoordinates(rec); // Crea un nuovo marker markers.value.addLayer(existingMarker); // console.log('***** Added marker TEMPORANEO', existingMarker) markerTemporaneo.value = existingMarker } if (existingMarker) { const lat = existingMarker.getLatLng().lat const lng = existingMarker.getLatLng().lng recordShowed.value = rec markerShowed.value = existingMarker // console.log('flyToCoord START ... ', lat, lng) // Passa una callback dopo il volo flyToCoord(lat, lng, () => { // console.log('flyToCoord END ... ', lat, lng) if (markerShowed.value) { //console.log('openPopup markerShowed', markerShowed.value) if (markerShowed.value.closePopup) { markerShowed.value.openPopup(); // Mostra il popup } } }); } } return { mywidth, myheight, map, iconWidth, iconHeight, iconUrl, iconSize, changeIcon, zoom, log, getCoordinates, arrcord, getCurrentPosition, isTrackingLocation, visiblePosition, gotoCurrentLocation, showInMap, } } })