fix: pin dimensions match Kartographer mapbox-lib.js exactly
Kartographer/mapbox-lib.js defines:
sizes = { small:[20,50], medium:[30,70], large:[35,90] }
iconSize: sizes[size] <- CSS stretches image to this
Previous: pin-m=27x41 -> CSS stretched to 30x70 (+11% h, +71% v)
Result: slim tip distorted into fat oval shape
Fix: generate images at exact expected dimensions:
pin-s: 20x50, pin-m: 30x70, pin-l: 35x90 (@1x)
pin-m@2x: 60x140
Geometry: r=w*0.47 (circle fills width), cy=r+1, tipY=h-1
This commit is contained in:
parent
641312aba9
commit
bedbe0f3f3
4 changed files with 41 additions and 13 deletions
|
|
@ -237,7 +237,7 @@ docker compose logs -f tileserver # Raster-Rendering
|
||||||
- Image: `192.168.178.6:8083/cschulz/rd13_tile_server-marker-api:latest` (Forgejo Registry)
|
- Image: `192.168.178.6:8083/cschulz/rd13_tile_server-marker-api:latest` (Forgejo Registry)
|
||||||
- API Root: `http://localhost:9984`
|
- API Root: `http://localhost:9984`
|
||||||
- Endpunkt: `/styles/v4/marker/{type}+{hexcolor}(@{scale}x).png`
|
- Endpunkt: `/styles/v4/marker/{type}+{hexcolor}(@{scale}x).png`
|
||||||
- Typen: `pin-s` (20×30px), `pin-m` (27×41px, Maptiler-Standard), `pin-l` (34×52px); 85% opak, weißer Rand + Innenpunkt
|
- Typen: `pin-s` (20×50px), `pin-m` (30×70px), `pin-l` (35×90px) @1x – exakte Kartographer-Maße (mapbox-lib.js `sizes`); weißer Rand + Innenpunkt, 85% opak
|
||||||
- Image neu bauen: `docker compose build marker-api && docker compose up -d marker-api`
|
- Image neu bauen: `docker compose build marker-api && docker compose up -d marker-api`
|
||||||
- CI: Forgejo baut + pusht automatisch bei Änderungen in `services/marker-api/`
|
- CI: Forgejo baut + pusht automatisch bei Änderungen in `services/marker-api/`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,28 @@ Geometry-Fix: r=35.5% der Breite, tipY=97.5%, Spitze passt jetzt sauber in die C
|
||||||
### Prompt 13
|
### Prompt 13
|
||||||
«Das sieht aber immer noch komisch aus...»
|
«Das sieht aber immer noch komisch aus...»
|
||||||
|
|
||||||
|
### Prompt 15
|
||||||
|
«Ich habe immer zwischen den tests den gesamten browser cache geleert das kann es nicht sein!»
|
||||||
|
|
||||||
|
### Antwort 15
|
||||||
|
Analyse der Kartographer-Quelldatei `/wikidata/extensions/Kartographer/lib/external/mapbox/mapbox-lib.js` (Zeilen 14773–14789):
|
||||||
|
|
||||||
|
```js
|
||||||
|
var sizes = { small: [20,50], medium: [30,70], large: [35,90] };
|
||||||
|
iconSize: sizes[size], // CSS-Zielgröße
|
||||||
|
iconAnchor: [sizes[size][0]/2, sizes[size][1]/2] // Anker = MITTE
|
||||||
|
```
|
||||||
|
|
||||||
|
Zwei Ursachen:
|
||||||
|
1. Größen-Mismatch: Kartographer erwartet pin-m = 30×70px. Wir lieferten 27×41px. CSS-Stretch: +11% horizontal / +71% vertikal → schlanke Spitze wird zu dickem Oval.
|
||||||
|
2. iconAnchor an der Mitte [15,35]: Funktioniert nur wenn Canvas wirklich 70px hoch ist.
|
||||||
|
|
||||||
|
Fix: baseSizes auf exakte Kartographer-Maße gesetzt:
|
||||||
|
- pin-s: 20×50, pin-m: 30×70, pin-l: 35×90
|
||||||
|
- Geometrie angepasst: r = w*0.47 (Kreis füllt Breite), cy=r+1, tipY=h-1
|
||||||
|
|
||||||
|
Verifiziert: pin-m@1x=30×70px, pin-m@2x=60×140px. Pin mit langer Spitze korrekt.
|
||||||
|
|
||||||
### Prompt 14
|
### Prompt 14
|
||||||
«besser aber immer noch nicht perfekt ich will es perfekt!! und ich will einen weißen rand und weißen punkt in der mitte wenn es geht»
|
«besser aber immer noch nicht perfekt ich will es perfekt!! und ich will einen weißen rand und weißen punkt in der mitte wenn es geht»
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# PROJECT_CONTEXT – rd13_tile_server
|
# PROJECT_CONTEXT – rd13_tile_server
|
||||||
|
|
||||||
**Letzte Aktualisierung:** 2026-07-01 – ✅ **Marker-API**: Go-Service für Maptiler-kompatible Marker-Endpunkte (`/styles/v4/marker/*`). Korrekte 27×41px Proportionen (Maptiler-Standard), weißer Rand (A=255), weißer Innenpunkt (A=255), 85% opaker Fill. Forgejo CI baut + pusht Image.
|
**Letzte Aktualisierung:** 2026-07-01 – ✅ **Marker-API**: Go-Service für Maptiler-kompatible Marker-Endpunkte (`/styles/v4/marker/*`). Maße exakt nach Kartographer mapbox-lib.js: pin-m=30×70px (@1x)/60×140px (@2x). Weißer Rand + Innenpunkt (A=255). Ursache der Verzerrung: Größen-Mismatch (27×41→30×70 CSS-Stretch). Forgejo CI baut + pusht Image.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,14 @@ var markerPattern = regexp.MustCompile(
|
||||||
// Der Pin ankert an der Spitze (bottom-center), nicht am Bildmittelpunkt.
|
// Der Pin ankert an der Spitze (bottom-center), nicht am Bildmittelpunkt.
|
||||||
type pinDims struct{ w, h float64 }
|
type pinDims struct{ w, h float64 }
|
||||||
|
|
||||||
|
// Maße MÜSSEN exakt den Werten in Kartographer's mapbox-lib.js entsprechen:
|
||||||
|
// sizes = { small: [20,50], medium: [30,70], large: [35,90] }
|
||||||
|
// Leaflet rendert das Bild per CSS auf genau diese Pixelgröße.
|
||||||
|
// Abweichungen → verzerrte Form (27×41 → 30×70 streckt Spitze um 71% vertikal).
|
||||||
var baseSizes = map[string]pinDims{
|
var baseSizes = map[string]pinDims{
|
||||||
"pin-s": {20, 30},
|
"pin-s": {20, 50},
|
||||||
"pin-m": {27, 41}, // Maptiler-Standard
|
"pin-m": {30, 70}, // mapbox-lib.js: sizes.medium = [30, 70]
|
||||||
"pin-l": {34, 52},
|
"pin-l": {35, 90},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marker-Cache (max 500 Einträge, reicht für alle Farb/Typ/Scale-Kombinationen)
|
// Marker-Cache (max 500 Einträge, reicht für alle Farb/Typ/Scale-Kombinationen)
|
||||||
|
|
@ -163,15 +167,17 @@ func generateMarker(pinType, hexColor string, scale float64) ([]byte, error) {
|
||||||
h = 15
|
h = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
// Geometrie: Kreis füllt ~74% der Breite, r/d ≈ 0.37 → Öffnungswinkel 22°
|
// Geometrie für 30×70 (@1x) / 60×140 (@2x):
|
||||||
// Entspricht exakt Maptiler pin-m Proportionen (27×41px @1x)
|
// - Kreis füllt fast die ganze Breite (r≈47% width)
|
||||||
|
// - iconAnchor=[w/2, h/2] in mapbox-lib.js → Anker liegt bei y=35 im Tail
|
||||||
|
// - Spitze bei y≈h-1: 34px unterhalb des Ankers (deutlich sichtbar)
|
||||||
cx := w / 2
|
cx := w / 2
|
||||||
r := w * 0.37 // Kreisradius: Kreis fast so breit wie Canvas
|
r := w * 0.47 // r≈14px (@1x): Kreis fast so breit wie Canvas
|
||||||
cy := r + h*0.04 // Kreismittelpunkt Y: kleiner oberer Rand
|
cy := r + 1.0 // cy≈15: Kreis berührt fast den oberen Rand
|
||||||
tipY := h - h*0.03 // Spitze Y: 3% Abstand vom unteren Rand
|
tipY := h - 1.0 // Spitze 1px vom unteren Rand
|
||||||
|
|
||||||
borderW := math.Max(2.0, w*0.08) // weißer Rand: gut sichtbar
|
borderW := math.Max(1.5, w*0.06) // weißer Rand
|
||||||
innerR := r * 0.38 // weißer Innenpunkt: 38% des Kreisradius
|
innerR := r * 0.36 // weißer Innenpunkt
|
||||||
|
|
||||||
// Füllfarbe: 85% opak; Rand und Punkt: vollständig weiß
|
// Füllfarbe: 85% opak; Rand und Punkt: vollständig weiß
|
||||||
fillBase := hexToColor(hexColor)
|
fillBase := hexToColor(hexColor)
|
||||||
|
|
@ -234,7 +240,7 @@ func handleMarker(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "image/png")
|
w.Header().Set("Content-Type", "image/png")
|
||||||
w.Header().Set("Cache-Control", "public, max-age=2592000, immutable")
|
w.Header().Set("Cache-Control", "public, max-age=86400")
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue