fix: marker pin 32x32 canvas, correct geometry, 80% opacity

- Square canvas (pin-m=32x32 @1x, 64x64 @2x) - fits MediaWiki slot
- r=35.5% of width, tipY=97.5%: teardrop no longer clipped
- 80% transparency: fill.A=204, white border A=220, inner dot A=204
This commit is contained in:
Conrad Schulz 2026-07-01 12:13:48 +00:00
parent 9df190aca8
commit 3960c9c5c1
4 changed files with 45 additions and 27 deletions

View file

@ -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` (24px), `pin-m` (32px), `pin-l` (40px) - Typen: `pin-s` (24px), `pin-m` (32px), `pin-l` (40px); Canvas quadratisch, 80% 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/`

View file

@ -95,10 +95,24 @@ Aufgeräumt:
- `docker-compose.yml` Image-Referenz aktualisiert - `docker-compose.yml` Image-Referenz aktualisiert
- Session-History und PROJECT_CONTEXT erstellt/aktualisiert - Session-History und PROJECT_CONTEXT erstellt/aktualisiert
Gesamtstruktur: ### Prompt 11
``` «so sehen die marker aus im media wiki warum sind sie farblos und warum abgeschnitten?»
rd13_tile_server (Forgejo Repo)
├── services/marker-api/ ← Go Code + Dockerfile ### Antwort 11
├── .forgejo/workflows/ ← CI baut + pusht nach Registry Zwei Probleme identifiziert:
└── docker-compose.yml ← nutzt Registry-Image 1. **Abgeschnitten**: Canvas war quadratisch, Teardrop-Spitze wurde unten abgeschnitten
``` 2. **Farblos**: `7e7e7e` ist das MediaWiki-Default wenn kein `marker-color` im GeoJSON gesetzt ist korrektes Verhalten
Geometry-Fix: r=35.5% der Breite, tipY=97.5%, Spitze passt jetzt sauber in die Canvas.
---
### Prompt 12
«Aber ich will doch das es in media wiki gut aussieht also muss es in 32x32 passen und gut aussehen. wäre es auch möglich ihn etwas durchsichtig zu machen?»
### Antwort 12
Zurück auf quadratische Canvas (pin-m=32×32 @1x, 64×64 @2x) mit optimierter Geometrie:
- `r=35.5%` der Breite (statt 29%) → Kreis füllt Canvas besser aus
- `tipY=97.5%` → Spitze immer noch vollständig sichtbar
- 80% Transparenz: `fill.A=204`, `white.A=220`
- Verifiziert: `pin-m@2x = 64×64px PNG`

View file

@ -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/*`) hinzugefügt. Forgejo CI baut + pusht Image in lokale Container-Registry. **Letzte Aktualisierung:** 2026-07-01 **Marker-API**: Go-Service für Maptiler-kompatible Marker-Endpunkte (`/styles/v4/marker/*`) hinzugefügt. 32×32px Canvas, 80% Transparenz, Google-Maps-Teardrop-Form. Forgejo CI baut + pusht Image in lokale Container-Registry.
--- ---

View file

@ -21,7 +21,7 @@ var markerPattern = regexp.MustCompile(
`^/styles/v4/marker/([a-z-]+)\+([0-9a-fA-F]{6})(?:@(\d+(?:\.\d+)?x))?\.png$`, `^/styles/v4/marker/([a-z-]+)\+([0-9a-fA-F]{6})(?:@(\d+(?:\.\d+)?x))?\.png$`,
) )
// Basis-Größen in logischen Pixeln // Basis-Größen in logischen Pixeln (quadratische Canvas)
var baseSizes = map[string]float64{ var baseSizes = map[string]float64{
"pin-s": 24, "pin-s": 24,
"pin-m": 32, "pin-m": 32,
@ -147,30 +147,34 @@ func generateMarker(pinType, hexColor string, scale float64) ([]byte, error) {
} }
markerCacheMu.RUnlock() markerCacheMu.RUnlock()
baseSize := baseSizes[pinType] bs, ok := baseSizes[pinType]
if baseSize == 0 { if !ok {
baseSize = 32 bs = baseSizes["pin-m"]
} }
size := math.Round(baseSize * scale) size := math.Round(bs * scale)
if size < 10 { if size < 12 {
size = 10 size = 12
} }
// Geometrie-Parameter // Geometrie: Teardrop in quadratische Canvas einpassen
// Kreis füllt obere 3/4, Spitze landet am unteren Rand
cx := size / 2 cx := size / 2
r := size * 0.29 // Kreisradius r := size * 0.355 // Kreisradius (rechts/links je 1px Puffer für Rand)
cy := r + size*0.03 // Kreismittelpunkt Y cy := r + size*0.02 // Kreismittelpunkt Y (kleiner oberer Rand)
tipY := size * 0.96 // Spitze Y tipY := size * 0.975 // Spitze Y (knapp vor unterem Rand)
borderW := math.Max(1.5, size*0.04) // Randbreite borderW := math.Max(1.2, size*0.045) // Randbreite
innerR := r * 0.38 // weißer Innenpunkt (Google-Maps-Look) innerR := r * 0.36 // weißer Innenpunkt
fill := hexToColor(hexColor) // Transparenz: 80% opak (Alpha 204)
white := color.RGBA{R: 255, G: 255, B: 255, A: 255} fillBase := hexToColor(hexColor)
fill := color.RGBA{R: fillBase.R, G: fillBase.G, B: fillBase.B, A: 204}
white := color.RGBA{R: 255, G: 255, B: 255, A: 220}
whiteDot := color.RGBA{R: 255, G: 255, B: 255, A: 204}
iSize := int(math.Ceil(size)) iSize := int(math.Ceil(size))
img := image.NewRGBA(image.Rect(0, 0, iSize, iSize)) img := image.NewRGBA(image.Rect(0, 0, iSize, iSize))
// 1. Weißer Rand (Pin mit leicht größerem Radius) // 1. Weißer Rand
borderPts := pinOutline(cx, cy, r+borderW, tipY, 64) borderPts := pinOutline(cx, cy, r+borderW, tipY, 64)
fillPolygon(img, borderPts, white) fillPolygon(img, borderPts, white)
@ -178,8 +182,8 @@ func generateMarker(pinType, hexColor string, scale float64) ([]byte, error) {
fillPts := pinOutline(cx, cy, r, tipY, 64) fillPts := pinOutline(cx, cy, r, tipY, 64)
fillPolygon(img, fillPts, fill) fillPolygon(img, fillPts, fill)
// 3. Weißer Innenpunkt (klassischer Google-Maps-Stil) // 3. Weißer Innenpunkt
drawCircle(img, cx, cy, innerR, white) drawCircle(img, cx, cy, innerR, whiteDot)
var buf bytes.Buffer var buf bytes.Buffer
if err := png.Encode(&buf, img); err != nil { if err := png.Encode(&buf, img); err != nil {