Auto deploy: 2025-12-09 06:00:27
This commit is contained in:
parent
4b7d8c3965
commit
ae2be1a71b
|
|
@ -1,108 +1,170 @@
|
|||
import maplibregl from "maplibre-gl";
|
||||
import { getCoords } from "./mapGeo";
|
||||
import { extractPostText } from "./mapFilter";
|
||||
|
||||
// Supprime tous les markers actuels
|
||||
/**
|
||||
* Supprime tous les marqueurs de la carte
|
||||
*/
|
||||
export function clearAllMarkers(markersRef, expandedElRef) {
|
||||
markersRef.current.forEach((m) => m.marker.remove());
|
||||
if (markersRef.current) {
|
||||
for (const item of markersRef.current) {
|
||||
try {
|
||||
item.marker.remove();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
markersRef.current = [];
|
||||
if (expandedElRef) {
|
||||
expandedElRef.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Crée un marker pour un post
|
||||
/**
|
||||
* Crée un DOM marker pour un post et l'ancre sur sa coordonnée.
|
||||
* - mapRef : ref vers la map MapLibre
|
||||
* - markersRef : ref vers la liste [{ id, marker, el, post }]
|
||||
* - expandedElRef : ref vers l'élément DOM du post actuellement "grand"
|
||||
*/
|
||||
export function createMarkerForPost(post, mapRef, markersRef, expandedElRef) {
|
||||
const map = mapRef.current;
|
||||
if (!map) return;
|
||||
|
||||
const coords = getCoords(post);
|
||||
if (!coords) return;
|
||||
// Récupère les coords (lat/lon / Lat/Lon / latitude/longitude)
|
||||
const lat =
|
||||
typeof post.lat === "number"
|
||||
? post.lat
|
||||
: typeof post.Lat === "number"
|
||||
? post.Lat
|
||||
: typeof post.latitude === "number"
|
||||
? post.latitude
|
||||
: null;
|
||||
|
||||
// évite les doublons (même id déjà affiché)
|
||||
if (
|
||||
typeof post.id === "number" &&
|
||||
markersRef.current.some((m) => m.id === post.id)
|
||||
) {
|
||||
const lon =
|
||||
typeof post.lon === "number"
|
||||
? post.lon
|
||||
: typeof post.Lon === "number"
|
||||
? post.Lon
|
||||
: typeof post.longitude === "number"
|
||||
? post.longitude
|
||||
: null;
|
||||
|
||||
if (lat == null || lon == null) {
|
||||
console.warn("Post sans coordonnée valide:", post);
|
||||
return;
|
||||
}
|
||||
|
||||
const [lngP, latP] = coords;
|
||||
if (
|
||||
typeof lngP !== "number" ||
|
||||
typeof latP !== "number" ||
|
||||
Number.isNaN(lngP) ||
|
||||
Number.isNaN(latP)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Petit texte (on garde court)
|
||||
const title = (post.title || post.Title || "").trim() || "Untitled";
|
||||
const snippet =
|
||||
(post.snippet || post.Snippet || "").trim() ||
|
||||
(post.body || post.Body || "").trim() ||
|
||||
title;
|
||||
|
||||
const { title, body, short } = extractPostText(post);
|
||||
// ELEMENT DOM DU MARKER
|
||||
const root = document.createElement("div");
|
||||
root.className = "post-marker post-marker-compact";
|
||||
|
||||
const compactHTML = `
|
||||
<div class="marker-inner">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-text">${short}</span>
|
||||
</div>
|
||||
`;
|
||||
const inner = document.createElement("div");
|
||||
inner.className = "marker-inner";
|
||||
|
||||
const expandedHTML = `
|
||||
<div class="marker-expanded-inner">
|
||||
<div class="marker-expanded-header">
|
||||
<div class="marker-dot"></div>
|
||||
<span class="marker-expanded-title">${title}</span>
|
||||
</div>
|
||||
<div class="marker-expanded-body">
|
||||
${body}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const dot = document.createElement("div");
|
||||
dot.className = "marker-dot";
|
||||
|
||||
const el = document.createElement("div");
|
||||
el.className = "post-marker post-marker-compact";
|
||||
el.innerHTML = compactHTML;
|
||||
const text = document.createElement("div");
|
||||
text.className = "marker-text";
|
||||
text.textContent = title;
|
||||
|
||||
inner.appendChild(dot);
|
||||
inner.appendChild(text);
|
||||
root.appendChild(inner);
|
||||
|
||||
// Marker MapLibre -> POSITION = [lon, lat] SANS OFFSET
|
||||
const marker = new maplibregl.Marker({
|
||||
element: el,
|
||||
anchor: "bottom",
|
||||
element: root,
|
||||
anchor: "bottom", // le bas du marker pointe sur la coordonnée
|
||||
})
|
||||
.setLngLat(coords)
|
||||
.setLngLat([lon, lat])
|
||||
.addTo(map);
|
||||
|
||||
const meta = {
|
||||
id: typeof post.id === "number" ? post.id : null,
|
||||
marker,
|
||||
el,
|
||||
compactHTML,
|
||||
expandedHTML,
|
||||
};
|
||||
markersRef.current.push(meta);
|
||||
// Sauvegarde pour pouvoir les nettoyer
|
||||
const entry = { id: post.id, marker, el: root, post };
|
||||
markersRef.current.push(entry);
|
||||
|
||||
const toggle = () => {
|
||||
if (expandedElRef.current && expandedElRef.current !== el) {
|
||||
const prev = markersRef.current.find(
|
||||
(m) => m.el === expandedElRef.current
|
||||
);
|
||||
if (prev) {
|
||||
prev.el.className = "post-marker post-marker-compact";
|
||||
prev.el.innerHTML = prev.compactHTML;
|
||||
}
|
||||
// Quand on clique -> on ouvre le gros post par-dessus, mais à la même coordonnée
|
||||
root.addEventListener("click", (ev) => {
|
||||
ev.stopPropagation();
|
||||
|
||||
// Fermer le précédent gros post
|
||||
if (expandedElRef.current && expandedElRef.current !== root) {
|
||||
collapseMarkerElement(expandedElRef.current);
|
||||
}
|
||||
|
||||
if (expandedElRef.current === el) {
|
||||
el.className = "post-marker post-marker-compact";
|
||||
el.innerHTML = compactHTML;
|
||||
// Toggle compact/expanded sur ce marker
|
||||
if (root.classList.contains("post-marker-expanded")) {
|
||||
collapseMarkerElement(root);
|
||||
expandedElRef.current = null;
|
||||
} else {
|
||||
el.className = "post-marker post-marker-expanded";
|
||||
el.innerHTML = expandedHTML;
|
||||
expandedElRef.current = el;
|
||||
expandMarkerElement(root, { title, snippet });
|
||||
expandedElRef.current = root;
|
||||
}
|
||||
};
|
||||
|
||||
el.addEventListener("click", toggle);
|
||||
el.addEventListener("touchend", (e) => {
|
||||
e.preventDefault();
|
||||
toggle();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Passe un marker en mode "grand post"
|
||||
*/
|
||||
function expandMarkerElement(root, { title, snippet }) {
|
||||
root.classList.remove("post-marker-compact");
|
||||
root.classList.add("post-marker-expanded");
|
||||
|
||||
// Nettoie l'intérieur et reconstruit
|
||||
root.innerHTML = "";
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.className = "marker-expanded-inner";
|
||||
|
||||
const header = document.createElement("div");
|
||||
header.className = "marker-expanded-header";
|
||||
|
||||
const dot = document.createElement("div");
|
||||
dot.className = "marker-dot";
|
||||
|
||||
const titleEl = document.createElement("div");
|
||||
titleEl.className = "marker-expanded-title";
|
||||
titleEl.textContent = title;
|
||||
|
||||
header.appendChild(dot);
|
||||
header.appendChild(titleEl);
|
||||
|
||||
const bodyEl = document.createElement("div");
|
||||
bodyEl.className = "marker-expanded-body";
|
||||
bodyEl.textContent = snippet;
|
||||
|
||||
container.appendChild(header);
|
||||
container.appendChild(bodyEl);
|
||||
|
||||
root.appendChild(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repasse un marker en mode petit post
|
||||
*/
|
||||
function collapseMarkerElement(root) {
|
||||
root.classList.remove("post-marker-expanded");
|
||||
root.classList.add("post-marker-compact");
|
||||
root.innerHTML = "";
|
||||
|
||||
const inner = document.createElement("div");
|
||||
inner.className = "marker-inner";
|
||||
|
||||
const dot = document.createElement("div");
|
||||
dot.className = "marker-dot";
|
||||
|
||||
const text = document.createElement("div");
|
||||
text.className = "marker-text";
|
||||
text.textContent = "…";
|
||||
|
||||
inner.appendChild(dot);
|
||||
inner.appendChild(text);
|
||||
root.appendChild(inner);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,12 @@
|
|||
/* IMPORTANT: on ne touche pas au transform du marker :
|
||||
MapLibre l'utilise pour placer le point. */
|
||||
|
||||
.post-marker {
|
||||
position: relative;
|
||||
transform: none !important; /* pas de translate chelou */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Petit post */
|
||||
.post-marker-compact {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.post-marker-expanded {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.marker-inner {
|
||||
/* Petit post compact */
|
||||
.post-marker-compact .marker-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
|
|
@ -27,25 +17,8 @@
|
|||
max-width: 220px;
|
||||
}
|
||||
|
||||
.marker-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
background: #3ec6ff;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.marker-text {
|
||||
color: #e8f5ff;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Gros post */
|
||||
.marker-expanded-inner {
|
||||
.post-marker-expanded .marker-expanded-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px 10px;
|
||||
|
|
@ -56,22 +29,4 @@
|
|||
max-width: 260px;
|
||||
}
|
||||
|
||||
.marker-expanded-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.marker-expanded-title {
|
||||
color: #f5fbff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.marker-expanded-body {
|
||||
color: #c7e3ff;
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
max-height: 120px;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* Etc… (le reste de ton style peut rester pareil) */
|
||||
|
|
|
|||
Loading…
Reference in New Issue