Files
myprojplanet_vite/src/components/CMapByTable/CMapByTable.ts

600 lines
17 KiB
TypeScript
Executable File

import { tools } from '@tools'
import { useQuasar } from 'quasar'
import type { PropType } from 'vue';
import { 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 'vue-i18n'
import { ICoordGPS } from '@src/model'
export default defineComponent({
name: 'CMapByTable',
emits: ['clickMarker', 'updateMapBoundaries', 'updateMapZoomOut'],
props: {
mytable: {
type: String,
required: true,
},
arrcordprop: {
type: Array as PropType<any[]>,
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(<any>null);
const visiblePosition = ref(false)
const markers = shallowRef(<any>null);
const isTrackingLocation = ref(false)
const debug = ref(tools.isDevelop())
const currentMarkerPositionGPS = shallowRef<L.Marker | null>(null)
const centerCoordinates = ref<{ lat: number; lng: number }>({ lat: 0, lng: 0 }); //
const arrMarkers = ref(<any>[])
const recordShowed = ref(<any>null)
const markerShowed = shallowRef<any>(null)
const markerTemporaneo = shallowRef<L.Marker | null>(null)
const mapOptions = ref(<any>{
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: '<span class="material-icons">location_on</span>',
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, 'arrcordprop')
const precZoomLevel = ref(0)
const debounceTimer = ref(<any>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.value, () => {
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'
const 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 = `
<div class="marker-wrapper">
<img src="/images/marker-shadow.png" class="marker-shadow" alt="Shadow" />
<img src="/images/icon.png" class="marker-icon" alt="" />
<div class="marker-circle"></div>
<div class="marker-mini-icon ${getIconName(rec)}"></div>
</div>`;
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
const each_marker = new L.marker(
[rec.coordinate_gps.coordinates[1], rec.coordinate_gps.coordinates[0]],
{
icon: markerIcon
}
)
.bindPopup(() => {
const container = L.DomUtil.create('div');
const strHTML = `<span class="fake-link">${rec.descr}</span>`
if (debug.value) {
// strHTML += `<br> Lat: ${rec.coordinate_gps.coordinates[1]} <br> Lng: ${rec.coordinate_gps.coordinates[0]}`;
}
container.innerHTML = strHTML
const 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,
}
}
})