server_photo_s85js/public/js/map/activities/activityMarkers.js.ok4
2026-08-11 08:45:04 +02:00

477 lines
8.2 KiB
Text

// public/js/map/activities/activityMarkers.js
// ===================================
// MAPBOX ACTIVITY MARKERS
// ===================================
(() => {
"use strict";
let mapboxMap = null;
const markers = new Map();
const SOURCE_ID = "activities";
// ===================================
// SET MAP
// ===================================
function setMap(map) {
mapboxMap = map;
console.log("[ActivityMarkers] setMap");
}
// ===================================
// CREA ELEMENTO ATTIVITÀ
// ===================================
function createActivityElement(feature) {
const el = document.createElement("div");
el.className = "activity-marker";
/*
* Per ora usiamo un marker semplice.
*
* In seguito possiamo sostituirlo con:
* - icona attività
* - colore per categoria
* - stato attività
* - durata
* - popup
* - icona personalizzata
*/
el.style.width = "18px";
el.style.height = "18px";
el.style.borderRadius = "50%";
el.style.background = "#008cff";
el.style.border = "2px solid #ffffff";
el.style.boxSizing = "border-box";
el.style.cursor = "pointer";
el.style.boxShadow =
"0 1px 4px rgba(0,0,0,0.35)";
return el;
}
// ===================================
// CLICK ATTIVITÀ
// ===================================
function handleActivityClick(feature) {
if (!feature) {
return;
}
const id = String(
feature.properties?.id ?? "",
);
console.log(
"[ActivityMarkers] click",
{
id,
feature,
},
);
/*
* API futura.
*
* Quando avremo il modello definitivo
* delle attività possiamo collegare qui
* il relativo pannello/dettaglio.
*/
if (
typeof window.openActivityMapItem ===
"function"
) {
const items =
typeof window.getLocalActivities ===
"function"
? window.getLocalActivities()
: [];
const item = items.find(
(activity) =>
String(activity.id) === id,
);
if (item) {
window.openActivityMapItem(item);
return;
}
}
/*
* Fallback temporaneo.
*/
console.log(
"[ActivityMarkers] attività selezionata:",
id,
);
}
// ===================================
// CREA MARKER
// ===================================
function createMarker(feature) {
if (!mapboxMap) {
return null;
}
if (!feature) {
return null;
}
const id = String(
feature.properties?.id ?? "",
);
if (!id) {
console.warn(
"[ActivityMarkers] attività senza id",
feature,
);
return null;
}
// ---------------------------------
// EVITA DUPLICATI
// ---------------------------------
if (markers.has(id)) {
const marker =
markers.get(id);
if (
feature.geometry?.coordinates
) {
marker.setLngLat(
feature.geometry.coordinates,
);
}
return marker;
}
// ---------------------------------
// ELEMENTO HTML
// ---------------------------------
const el =
createActivityElement(feature);
// ---------------------------------
// CLICK
// ---------------------------------
el.addEventListener(
"click",
(event) => {
event.stopPropagation();
handleActivityClick(feature);
},
);
// ---------------------------------
// MAPBOX MARKER
// ---------------------------------
const marker =
new mapboxgl.Marker({
element: el,
anchor: "center",
})
.setLngLat(
feature.geometry.coordinates,
)
.addTo(mapboxMap);
marker.__activityId = id;
marker.__originalLngLat =
feature.geometry.coordinates;
markers.set(id, marker);
return marker;
}
// ===================================
// GET VISIBLE IDS
// ===================================
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) =>
feature.properties?.id,
)
.filter(
(id) =>
id !== undefined &&
id !== null,
)
.map((id) => String(id)),
);
}
// ===================================
// UPDATE
// ===================================
function update(features = []) {
if (!mapboxMap) {
return;
}
if (!mapboxMap.getSource(SOURCE_ID)) {
return;
}
const visibleIds =
getVisibleIds();
console.log(
"[ActivityMarkers] visibility",
{
features: features.length,
visible: visibleIds.size,
},
);
// ===================================
// RIMUOVI ATTIVITÀ CLUSTERIZZATE
// ===================================
for (
const [
id,
marker,
] of markers
) {
if (
!visibleIds.has(String(id))
) {
marker.remove();
markers.delete(id);
}
}
// ===================================
// CREA / AGGIORNA
// ===================================
for (const feature of features) {
if (!feature) {
continue;
}
if (
!feature.geometry?.coordinates
) {
continue;
}
const id = String(
feature.properties?.id ?? "",
);
if (!id) {
continue;
}
/*
* Se l'attività è dentro un cluster,
* non deve avere il marker HTML.
*/
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
// ---------------------------------
createMarker(feature);
}
// ===================================
// RIMOZIONE FINALE
// ===================================
for (
const [
id,
marker,
] of markers
) {
if (
!visibleIds.has(String(id))
) {
marker.remove();
markers.delete(id);
}
}
}
// ===================================
// 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(
"[ActivityMarkers] debug",
{
markers:
markers.size,
ids:
[...markers.keys()],
},
);
}
// ===================================
// API PUBBLICA
// ===================================
window.MapboxActivityMarkers = {
setMap,
update,
createMarker,
getVisibleIds,
get,
getAll,
remove,
clear,
size,
debug,
};
})();