447 lines
7.6 KiB
JavaScript
447 lines
7.6 KiB
JavaScript
// 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";
|
|
|
|
el.innerHTML = `
|
|
<div class="activity-marker-inner"></div>
|
|
`;
|
|
|
|
return el;
|
|
}
|
|
|
|
// ===================================
|
|
// CLICK ATTIVITÀ
|
|
// ===================================
|
|
|
|
function handleActivityClick(feature) {
|
|
if (!feature) {
|
|
return;
|
|
}
|
|
|
|
const id = String(
|
|
feature.properties?.id ?? "",
|
|
);
|
|
|
|
console.log("[ActivityMarkers] click", {
|
|
id,
|
|
feature,
|
|
});
|
|
|
|
/*
|
|
* Se esiste un handler globale
|
|
* per l'apertura dell'attività,
|
|
* lo utilizziamo.
|
|
*/
|
|
|
|
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 generico.
|
|
*
|
|
* Non facciamo nulla se il progetto
|
|
* non espone ancora un handler.
|
|
*/
|
|
}
|
|
|
|
// ===================================
|
|
// CREA MARKER
|
|
// ===================================
|
|
|
|
function createMarker(feature) {
|
|
if (!mapboxMap) {
|
|
return null;
|
|
}
|
|
|
|
if (!feature) {
|
|
return null;
|
|
}
|
|
|
|
const id = String(
|
|
feature.properties?.id ?? "",
|
|
);
|
|
|
|
if (!id) {
|
|
console.warn(
|
|
"[ActivityMarkers] feature senza id",
|
|
feature,
|
|
);
|
|
|
|
return null;
|
|
}
|
|
|
|
/*
|
|
* Evitiamo duplicati.
|
|
*/
|
|
|
|
if (markers.has(id)) {
|
|
return markers.get(id);
|
|
}
|
|
|
|
const coordinates =
|
|
feature.geometry?.coordinates;
|
|
|
|
if (
|
|
!coordinates ||
|
|
coordinates.length < 2
|
|
) {
|
|
console.warn(
|
|
"[ActivityMarkers] coordinate non valide",
|
|
feature,
|
|
);
|
|
|
|
return null;
|
|
}
|
|
|
|
const el =
|
|
createActivityElement(feature);
|
|
|
|
// =================================
|
|
// CLICK
|
|
// =================================
|
|
|
|
el.addEventListener(
|
|
"click",
|
|
(event) => {
|
|
event.stopPropagation();
|
|
|
|
handleActivityClick(feature);
|
|
},
|
|
);
|
|
|
|
// =================================
|
|
// MARKER MAPBOX
|
|
// =================================
|
|
|
|
const marker =
|
|
new mapboxgl.Marker({
|
|
element: el,
|
|
|
|
anchor: "center",
|
|
})
|
|
.setLngLat(coordinates)
|
|
.addTo(mapboxMap);
|
|
|
|
marker.__activityId = id;
|
|
|
|
marker.__originalLngLat =
|
|
coordinates;
|
|
|
|
markers.set(id, marker);
|
|
|
|
return marker;
|
|
}
|
|
|
|
// ===================================
|
|
// ATTIVITÀ 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) =>
|
|
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 MARKER CLUSTERIZZATI
|
|
// =================================
|
|
|
|
for (
|
|
const [
|
|
id,
|
|
marker,
|
|
] of markers
|
|
) {
|
|
if (!visibleIds.has(id)) {
|
|
marker.remove();
|
|
|
|
markers.delete(id);
|
|
}
|
|
}
|
|
|
|
// =================================
|
|
// CREA / AGGIORNA
|
|
// =================================
|
|
|
|
for (const feature of features) {
|
|
if (!feature) {
|
|
continue;
|
|
}
|
|
|
|
const id = String(
|
|
feature.properties?.id ?? "",
|
|
);
|
|
|
|
if (!id) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Se l'attività è dentro un cluster
|
|
* non mostriamo il marker singolo.
|
|
*/
|
|
|
|
if (!visibleIds.has(id)) {
|
|
continue;
|
|
}
|
|
|
|
const coordinates =
|
|
feature.geometry?.coordinates;
|
|
|
|
if (
|
|
!coordinates ||
|
|
coordinates.length < 2
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
// --------------------------------
|
|
// MARKER ESISTENTE
|
|
// --------------------------------
|
|
|
|
if (markers.has(id)) {
|
|
const marker =
|
|
markers.get(id);
|
|
|
|
marker.setLngLat(
|
|
coordinates,
|
|
);
|
|
|
|
marker.__originalLngLat =
|
|
coordinates;
|
|
|
|
marker
|
|
.getElement()
|
|
.style.display = "";
|
|
|
|
continue;
|
|
}
|
|
|
|
// --------------------------------
|
|
// CREA MARKER
|
|
// --------------------------------
|
|
|
|
createMarker(feature);
|
|
}
|
|
|
|
// =================================
|
|
// RIMOZIONE FINALE
|
|
// =================================
|
|
|
|
for (
|
|
const [
|
|
id,
|
|
marker,
|
|
] of markers
|
|
) {
|
|
if (!visibleIds.has(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,
|
|
};
|
|
})();
|