From e5811f03fb30ced245d9457f7d440ccc8b88cefd Mon Sep 17 00:00:00 2001 From: Pepe Ziberi Date: Thu, 23 Jul 2026 22:30:22 +0200 Subject: [PATCH] fix(map): Pfeilspitze zeigt exakt entlang der Linie (v1.8.10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Pfeilspitze wurde mit dem geografischen Winkel (atan2 auf lng/lat) gedreht, der wegen der Mercator-Verzerrung nicht mit der auf dem Bildschirm gezeichneten Linie übereinstimmt (v.a. bei nördlichen Breiten). Jetzt aus den projizierten Pixeln berechnet (viewport- ausgerichtet) → Spitze zeigt korrekt in Linienrichtung. Co-Authored-By: Claude Opus 4.8 (1M context) --- package.json | 2 +- src/components/map/map-view.tsx | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 3f304db..16774fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lageplan", - "version": "1.8.9", + "version": "1.8.10", "description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation", "private": true, "scripts": { diff --git a/src/components/map/map-view.tsx b/src/components/map/map-view.tsx index 74cc6be..b698126 100644 --- a/src/components/map/map-view.tsx +++ b/src/components/map/map-view.tsx @@ -1489,27 +1489,31 @@ export function MapView({ const lineCoords = f.geometry.coordinates as number[][] if (lineCoords.length < 2) return - // Geographic bearing from p1 to p2 (works for short distances) const p1 = lineCoords[lineCoords.length - 2] const p2 = lineCoords[lineCoords.length - 1] - const dLng = p2[0] - p1[0] - const dLat = p2[1] - p1[1] - // atan2(dLng, dLat) gives angle from north (up), clockwise — matches CSS triangle ▲ default - const geoBearing = Math.atan2(dLng, dLat) * (180 / Math.PI) + // Bildschirm-Winkel aus projizierten Pixeln berechnen — der geografische Winkel + // (atan2 auf lng/lat) stimmt wegen der Mercator-Verzerrung NICHT mit der auf dem + // Bildschirm gezeichneten Linie überein (v.a. bei nördlichen Breiten). So zeigt die + // Spitze exakt entlang der Linie. + const a = map.current.project(p1 as [number, number]) + const b = map.current.project(p2 as [number, number]) + // CSS-Dreieck zeigt nach oben (−y). Winkel im Uhrzeigersinn von „oben". + const screenAngle = Math.atan2(b.x - a.x, -(b.y - a.y)) * (180 / Math.PI) const color = (f.properties.color as string) || '#000000' const arrowEl = document.createElement('div') arrowEl.style.cssText = ` width: 0; height: 0; - border-left: 12px solid transparent; - border-right: 12px solid transparent; - border-bottom: 24px solid ${color}; - transform: rotate(${geoBearing}deg); + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 20px solid ${color}; + transform: rotate(${screenAngle}deg); transform-origin: center center; pointer-events: none; ` - const marker = new maplibregl.Marker({ element: arrowEl, anchor: 'center', rotationAlignment: 'map' }) + // Viewport-ausgerichtet (Bildschirm), passend zum bildschirm-basierten Winkel. + const marker = new maplibregl.Marker({ element: arrowEl, anchor: 'center' }) .setLngLat(p2 as [number, number]) .addTo(map.current) markersRef.current.push(marker)