server_photo_s85js/public/js/map/photos/photoMarkers.js
2026-08-11 08:45:04 +02:00

406 lines
7.1 KiB
JavaScript

// 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,
};
})();