// public/js/map/photos/photoMarkers.js // =================================== // MAPBOX PHOTO MARKERS // =================================== (() => { "use strict"; let mapboxMap = null; const markers = new Map(); const SOURCE_ID = "photos"; // =================================== // SET MAP // =================================== function setMap(map) { mapboxMap = map; console.log("[PhotoMarkers] setMap"); } // =================================== // CREA ELEMENTO FOTO // =================================== function createPhotoElement(feature) { const img = document.createElement("img"); img.src = feature.properties?.thumb || ""; img.width = 46; img.height = 46; img.style.borderRadius = "7px"; img.style.objectFit = "cover"; img.style.border = "2px solid white"; img.style.cursor = "pointer"; return img; } // =================================== // CLICK FOTO // =================================== function handlePhotoClick(feature) { if (!feature) { return; } const id = String( feature.properties?.id, ); // ================================= // FOTO VICINE // ================================= if ( window.MapboxPhotoSpiderfy ?.getNearbyPhotos ) { const nearbyPhotos = window.MapboxPhotoSpiderfy.getNearbyPhotos( feature, 3, ); console.log( "[PhotoMarkers] foto entro 3 metri:", nearbyPhotos.length, ); if (nearbyPhotos.length > 1) { window.MapboxPhotoSpiderfy.spiderfyPhotos( nearbyPhotos, ); return; } } // ================================= // APERTURA FOTO // ================================= const items = typeof window.getLocalItems === "function" ? window.getLocalItems() : []; const item = items.find( (photo) => String(photo.id) === id, ); if (item) { window.openPhotoMapItem?.(item); } // ================================= // CHIUDI EVENTUALE SPIDERFY // ================================= window.MapboxPhotoSpiderfy ?.clear?.(); } // =================================== // CREA MARKER // =================================== function createMarker(feature) { if (!mapboxMap) { return null; } const id = String( feature.properties?.id, ); // Evita duplicati. if (markers.has(id)) { return markers.get(id); } const img = createPhotoElement(feature); img.addEventListener( "click", (event) => { event.stopPropagation(); handlePhotoClick(feature); }, ); const marker = new mapboxgl.Marker({ element: img, }) .setLngLat( feature.geometry.coordinates, ) .addTo(mapboxMap); marker.__originalLngLat = feature.geometry.coordinates; marker.__photoId = id; /* * Questo marker appartiene * esclusivamente ai marker normali. * * Gli spider marker sono gestiti * da photoSpiderfy.js. */ marker.__spider = false; markers.set(id, marker); return marker; } // =================================== // FOTO VISIBILI // =================================== function getVisibleIds() { if (!mapboxMap) { return new Set(); } if ( !mapboxMap.getSource( SOURCE_ID, ) ) { return new Set(); } const sourcePoints = mapboxMap.querySourceFeatures( SOURCE_ID, { filter: [ "!", ["has", "point_count"], ], }, ); return new Set( sourcePoints.map( (feature) => String( feature.properties?.id, ), ), ); } // =================================== // UPDATE // =================================== function update(features = []) { if (!mapboxMap) { return; } if (!mapboxMap.isStyleLoaded()) { return; } const visibleIds = getVisibleIds(); console.log( "[PhotoMarkers] visibility", { features: features.length, visible: visibleIds.size, }, ); // ================================= // RIMUOVI FOTO CLUSTERIZZATE // ================================= for ( const [ id, marker, ] of markers ) { /* * Se una foto non è più un punto * individuale della source, significa * che è stata assorbita da un cluster. */ if ( !visibleIds.has(id) ) { marker.remove(); markers.delete(id); } } // ================================= // CREA / AGGIORNA FOTO // ================================= for (const feature of features) { const id = String( feature.properties?.id, ); // -------------------------------- // FOTO DENTRO UN CLUSTER // -------------------------------- if ( !visibleIds.has(id) ) { continue; } // -------------------------------- // MARKER ESISTENTE // -------------------------------- if ( markers.has(id) ) { const marker = markers.get(id); marker.setLngLat( feature.geometry.coordinates, ); marker.__originalLngLat = feature.geometry.coordinates; continue; } // -------------------------------- // CREA MARKER // -------------------------------- createMarker(feature); } } // =================================== // GET MARKER // =================================== function get(id) { return markers.get( String(id), ); } // =================================== // GET ALL // =================================== function getAll() { return markers; } // =================================== // REMOVE // =================================== function remove(id) { const key = String(id); const marker = markers.get(key); if (!marker) { return; } marker.remove(); markers.delete(key); } // =================================== // CLEAR // =================================== function clear() { for ( const marker of markers.values() ) { marker.remove(); } markers.clear(); } // =================================== // SIZE // =================================== function size() { return markers.size; } // =================================== // DEBUG // =================================== function debug() { console.log( "[PhotoMarkers] debug", { markers: markers.size, ids: [...markers.keys()], }, ); } // =================================== // PUBLIC API // =================================== window.MapboxPhotoMarkers = { setMap, update, createMarker, getVisibleIds, get, getAll, remove, clear, size, debug, }; })();