From 4df29e7e6c06916d19c3362dde6d050e1abd9967 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 20:50:57 +0200 Subject: [PATCH] =?UTF-8?q?Linien-Label=20flackert=20nicht=20mehr,=20Hover?= =?UTF-8?q?-K=C3=A4rtchen=20f=C3=A4hrt=20mit=20dem=20Zug=20mit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb --- web/app.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/web/app.js b/web/app.js index 694204c..09a9de2 100644 --- a/web/app.js +++ b/web/app.js @@ -77,7 +77,9 @@ const map = new maplibregl.Map({ layout: { "text-field": ["get", "line"], "text-font": ["Noto Sans Medium"], "text-size": 11, - "text-offset": [0, 1.1], "text-anchor": "top", "text-optional": true, + "text-offset": [0, 1.1], "text-anchor": "top", + // nicht bei jedem Animationsschritt neu auf Überschneidung prüfen, sonst flackert die Linie + "text-allow-overlap": true, "text-ignore-placement": true, }, paint: { "text-color": "#111827", "text-halo-color": "#fff", "text-halo-width": 1.5 } }, ], @@ -210,6 +212,10 @@ function render() { f.properties.bearing = cur === undefined ? target : cur + turn(cur, target) * ease; } map.getSource("trains").setData(trains); + if (hoverId) { // Hover-Kärtchen fährt mit dem Zug mit + const f = trains.features.find((x) => x.properties.id === hoverId); + if (f) hover.setLngLat(f.geometry.coordinates); else { hover.remove(); hoverId = null; } + } } let lastFrame = 0; @@ -291,14 +297,19 @@ document.getElementById("close").onclick = closeTrip; map.on("click", "trains", (e) => showTrip(e.features[0].properties.id)); const hover = new maplibregl.Popup({ closeButton: false, closeOnClick: false, offset: 12, className: "hover" }); +let hoverId = null; +function hoverHtml(p) { + const delay = p.delay === undefined || p.delay === null ? "" : delayText(Number(p.delay)) || 'pünktlich'; + return `${esc(p.line)} ${esc(p.nr)} ${delay}
nach ${esc(p.to)}`; +} map.on("mousemove", "trains", (e) => { map.getCanvas().style.cursor = "pointer"; const p = e.features[0].properties; - const delay = p.delay === undefined || p.delay === null ? "" : delayText(Number(p.delay)) || 'pünktlich'; - hover.setLngLat(e.features[0].geometry.coordinates) - .setHTML(`${esc(p.line)} ${esc(p.nr)} ${delay}
nach ${esc(p.to)}`).addTo(map); + if (p.id !== hoverId) hover.setHTML(hoverHtml(p)); + hoverId = p.id; + hover.setLngLat(e.features[0].geometry.coordinates).addTo(map); }); -map.on("mouseleave", "trains", () => { map.getCanvas().style.cursor = ""; hover.remove(); }); +map.on("mouseleave", "trains", () => { map.getCanvas().style.cursor = ""; hover.remove(); hoverId = null; }); map.on("load", () => { let mode = "light";