gallery_server_client_s190js/public/js/map/photosLayer.js
2026-10-26 11:00:14 +01:00

411 lines
9 KiB
JavaScript

// public/js/mapPhotosLayer.js
// ===============================
// LAYER MAPPA FOTO
// ===============================
(function () {
let visiblePhotoMarkers = new Map();
let mapPhotoItems = [];
let mapPhotoById = new Map();
let mapPhotoLoadPromise = null;
let mapPhotoLoadGeneration = 0;
let mapPhotoIndexLoaded = false;
let mapPhotoBoundsKey = null;
let mapPhotoRequestedBoundsKey = null;
function getPhotoMapBounds() {
const bounds = window.MapEngine?.getBounds?.() || window.globalMap?.getBounds?.();
if (!bounds) return null;
const west = bounds.getWest();
const south = bounds.getSouth();
const east = bounds.getEast();
const north = bounds.getNorth();
if (![west, south, east, north].every(Number.isFinite)) {
return null;
}
return {
west, south, east, north,
key: [west, south, east, north]
.map(v => v.toFixed(5)).join(","),
};
}
async function loadMapPhotoIndex() {
const bounds = getPhotoMapBounds();
if (!bounds) return false;
if (mapPhotoIndexLoaded && mapPhotoBoundsKey === bounds.key) {
return true;
}
if (
mapPhotoLoadPromise &&
mapPhotoRequestedBoundsKey === bounds.key
) {
return mapPhotoLoadPromise;
}
const token = localStorage.getItem("token");
if (!token) return false;
const generation = ++mapPhotoLoadGeneration;
mapPhotoRequestedBoundsKey = bounds.key;
mapPhotoIndexLoaded = false;
const params = new URLSearchParams({
west: String(bounds.west),
south: String(bounds.south),
east: String(bounds.east),
north: String(bounds.north),
limit: "2500",
});
if (localStorage.getItem("showDeleted") === "1") {
params.set("showDeleted", "1");
}
const promise = (async () => {
try {
const response = await fetch(
"/photos/map?" + params.toString(),
{
headers: { Authorization: "Bearer " + token },
}
);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
const data = await response.json();
if (generation !== mapPhotoLoadGeneration) return false;
if (!Array.isArray(data.items)) {
throw new Error("Risposta map senza array items");
}
mapPhotoItems = data.items.filter(item =>
Number.isFinite(Number(item.gps?.lat)) &&
Number.isFinite(Number(item.gps?.lng))
);
mapPhotoById = new Map(
mapPhotoItems.map(item => [String(item.id), item])
);
window.MapSpatialIndex.build(mapPhotoItems);
mapPhotoBoundsKey = bounds.key;
mapPhotoIndexLoaded = true;
console.log("[mapPhotosLayer] area caricata", {
foto: mapPhotoItems.length,
truncated: Boolean(data.truncated),
bounds: bounds.key,
});
if (data.truncated) {
console.warn(
"[mapPhotosLayer] raggiunto il limite di risultati; ingrandisci la mappa"
);
}
window.renderPhotoMapLayer?.();
return true;
} catch (error) {
if (generation === mapPhotoLoadGeneration) {
console.error("[mapPhotosLayer] caricamento area fallito:", error);
}
return false;
} finally {
if (generation === mapPhotoLoadGeneration) {
mapPhotoLoadPromise = null;
}
}
})();
mapPhotoLoadPromise = promise;
return promise;
}
window.getMapPhotoItem = function (id) {
return mapPhotoById.get(String(id)) || null;
};
window.refreshMapPhotoIndex = function () {
mapPhotoLoadGeneration++;
mapPhotoLoadPromise = null;
mapPhotoIndexLoaded = false;
mapPhotoBoundsKey = null;
mapPhotoRequestedBoundsKey = null;
mapPhotoItems = [];
mapPhotoById.clear();
window.MapSpatialIndex?.build?.([]);
window.clearPhotoMapLayer?.(false);
return loadMapPhotoIndex();
};
window.clearPhotoMapLayer =
function (clearFactoryCache = false) {
if (window.globalMarkers) {
visiblePhotoMarkers =
MapLayerManager.sync(
window.globalMarkers,
visiblePhotoMarkers,
[],
);
} else {
visiblePhotoMarkers.clear();
}
if (clearFactoryCache) {
PhotoMarkerFactory.clear();
}
console.log(
"[mapPhotosLayer] marker Leaflet puliti",
{
visible:
visiblePhotoMarkers.size,
cache:
PhotoMarkerFactory.size(),
clusterLayers:
window.globalMarkers
?.getLayers?.()
?.length ?? null,
},
);
};
window.photoMapDebug = {
cacheSize() {
return PhotoMarkerFactory.size();
},
visibleSize() {
return visiblePhotoMarkers.size;
},
clearCache() {
window.clearPhotoMapLayer?.(
true,
);
},
};
// ===============================
// APRI FOTO
// ===============================
window.openPhotoMapItem = function (item) {
const thumb = toAbsoluteUrl(
item.thub1 || item.thub2 || item.path,
item.name,
"thumbs",
item.cartella,
);
const original = toAbsoluteUrl(
item.path,
item.name,
"original",
item.cartella,
);
window.openModal(item);
//window.openModal?.(original, thumb, item);
};
// ===============================
// RENDER FOTO
// ===============================
window.renderPhotoMapLayer =
function () {
if (
window.state?.mode !==
"photos"
) {
return;
}
if (!window.globalMap) {
return;
}
if (!window.MapEngine?.isReady?.()) {
console.warn("[mapPhotosLayer] MapEngine non pronto");
return;
}
const bounds = window.MapEngine?.getBounds?.() || window.globalMap.getBounds();
const area = getPhotoMapBounds();
if (
!area ||
!mapPhotoIndexLoaded ||
mapPhotoBoundsKey !== area.key
) {
loadMapPhotoIndex();
return;
}
const items = MapSpatialIndex.search(bounds);
const markers = [];
for (const entry of items) {
const lat = entry.lat;
const lng = entry.lng;
const photo = entry.item;
if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
continue;
}
const marker = PhotoMarkerFactory.get(photo);
markers.push(marker);
}
visiblePhotoMarkers = MapLayerManager.sync(
window.globalMarkers,
visiblePhotoMarkers,
markers,
);
for (const marker of markers) {
if (
marker &&
!window.globalMarkers
?.hasLayer?.(marker)
) {
window.globalMarkers
?.addLayer?.(marker);
}
}
console.log(
"[mapPhotosLayer] marker sincronizzati",
{
visible:
visiblePhotoMarkers.size,
clusterLayers:
window.globalMarkers
?.getLayers?.()
?.length ?? null,
},
);
if (window.MapTerrain3D?.enabled?.()) {
const features = window.getPhotoMapGeoJSON?.() || [];
window.MapboxMarkers?.setPhotos(features);
}
console.log(
"[mapPhotosLayer]",
"visibili:",
visiblePhotoMarkers.size,
"cache:",
PhotoMarkerFactory.size(),
"indice:",
items.length,
);
};
// ===============================
// GEOJSON PER MAPBOX
// ===============================
window.getPhotoMapGeoJSON = function () {
const area = getPhotoMapBounds();
if (
!area ||
!mapPhotoIndexLoaded ||
mapPhotoBoundsKey !== area.key
) {
loadMapPhotoIndex();
return [];
}
const features = [];
let items = [];
/*
if (window.MapEngine?.isMapbox?.()) {
items = MapSpatialIndex.search({
getWest: () => -180,
getEast: () => 180,
getSouth: () => -90,
getNorth: () => 90,
});
} else {
const bounds = window.MapEngine?.getBounds?.();
items = bounds
? MapSpatialIndex.search(bounds)
: [];
}
*/
const bounds = window.MapEngine?.getBounds?.();
items = bounds ? MapSpatialIndex.search(bounds) : [];
console.log("[PhotoGeoJSON DEBUG bounds]", {
west: bounds?.getWest?.(),
east: bounds?.getEast?.(),
south: bounds?.getSouth?.(),
north: bounds?.getNorth?.(),
});
console.log("[PhotoGeoJSON DEBUG items]", items.length);
for (const entry of items) {
const lat = entry.lat;
const lng = entry.lng;
const photo = entry.item;
if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
continue;
}
features.push({
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat],
},
/* properties: {
id: photo.id,
type: "photo",
name: photo.name || "",
},*/
properties: {
id: photo.id,
type: "photo",
name: photo.name || "",
thumb: toAbsoluteUrl(
photo.thub1 || photo.thub2 || photo.path,
photo.name,
"thumbs",
photo.cartella,
),
},
});
}
return features;
};
})();