Zum Inhalt springen
Zurück zur Liste

Projects Map

Interaktive Projektkarte für die Interreg Baltic Sea Region

Jahr: 2021 JavaScriptLeafletPHP

Entstanden während meines Praktikums bei @iService: eine interaktive Karte, die die Projektpartnerschaften des EU-Programms Interreg Baltic Sea Region sichtbar macht. Die Karte zeigt, wer mit wem an welchem Programm arbeitet – über Ländergrenzen hinweg, mit hunderten Partnern an oft denselben Adressen.

Das Problem

Interreg fördert grenzüberschreitende Projekte. Wer als Forscherin, NGO oder Stadt einen Projektpartner sucht, möchte sehen, wer schon einmal mit ähnlichen Themen, in ähnlichen Regionen, in welchen Konstellationen kooperiert hat. Die Daten dafür existieren in einer WordPress-Datenbank, aber ohne räumlichen Bezug sind sie schwer zu durchsuchen. Ziel: eine Karte, auf der jede Partnerschaft als Linie zwischen Lead-Partner und Projektpartner sichtbar ist, mit Filtern nach Programm, Region und Projekt.

Rahmenbedingungen

Praktikumsprojekt mit definiertem Umfang, eingebettet in eine bestehende WordPress-Site. Datenquelle war ein Custom-Post-Type-Setup in WordPress, das ich nicht ändern konnte. Performance-Ziel: hunderte Marker und Tausende Linien gleichzeitig flüssig darstellen, auch auf älteren Notebooks. Visuelles Ziel: das Branding der Site nicht stören und einen Dark Mode für lange Sitzungen anbieten.

Architektur

Frontend ist Vanilla-JavaScript mit Leaflet als Kartenbibliothek. Für die Verbindungslinien (Flowmaps) zwischen Lead- und Projektpartnern kommt die Canvas Flowmap Layer Extension zum Einsatz – sie zeichnet auf einen Canvas-Layer statt SVG, was bei vielen Verbindungen mehrere Größenordnungen schneller ist.

Im Backend cached eine PHP-Schicht die Projektdaten aus WordPress-Custom-Post-Types in eine eigene JSON-Antwort, die das Frontend einmalig beim Laden zieht. So muss die Karte nicht bei jedem Filterwechsel ans WordPress – Filter laufen vollständig im Client. Filter-Kriterien sind Programm, Projektart und Region; ein Klick auf einen Marker öffnet ein Popup mit den Partner-Details.

Entscheidungen – und was verworfen wurde

Linien-Rendering: SVG → Canvas. Mein erster Versuch zeichnete jede Verbindung als SVG-Pfad. Bei ~3000 Linien fiel die Karte unter 10 fps. Der Wechsel auf den Canvas-Flowmap-Layer brachte die Performance zurück, weil der Browser nicht mehr jeden Pfad als eigenen DOM-Knoten verwalten musste. Tradeoff: Canvas-Pfade sind nicht direkt anklickbar – die Klick-Behandlung musste über die Marker laufen, nicht über die Linien selbst.

Cluster: Standard-Clustering → Kreisförmige Verteilung pro Adresse. Viele Lead-Partner sitzen an derselben Universitätsadresse. Mit Standard-Marker-Clustern wären 15 Partner an einer Stelle in einem Cluster verschwunden – das hätte den Sinn der Karte zerstört. Ich habe eine Funktion geschrieben, die Marker mit identischen Koordinaten in einem kleinen Kreis um den Ursprungspunkt verteilt; der Radius wächst mit der Anzahl. Cluster werden nur über echte räumliche Nachbarschaft gebildet, nicht über identische Punkte.

Daten-Layer: Direkter WordPress-Aufruf → PHP-Caching-Layer. Live-Aufrufe an WordPress wären für Updates ideal, kosteten aber zu viel Latenz. Die PHP-Cache-Schicht synchronisiert per Cron-Job alle paar Stunden – das ist für Projektdaten, die sich monatlich ändern, vollkommen ausreichend.

Theme: Custom-CSS → Leaflet-Tile-Switch. Statt eigene Karten-Renderer für Light/Dark zu schreiben, schaltet das Tool zwischen zwei Tile-Sources um (heller und dunkler Basemap-Stil). Das ist eine kleine Lösung mit großem Effekt, weil die Map-Bestandteile (Marker, Linien, Popups) ohnehin per CSS gestaltet sind.

Performance

Beim Erstaufruf werden Projektdaten als gebatchter JSON-Blob geladen (eine einzige Anfrage gegen die PHP-Cache-Schicht). Filterwechsel sind reine Client-Operationen ohne Netzwerk. Die Canvas-Flowmaps halten 60 fps auch beim Zoomen, weil das Re-Rendering pro Frame über Canvas-Operationen geht statt über DOM-Mutationen.

Was ich anders machen würde

TypeScript. Das Projekt war Vanilla-JS, was 2021 noch eine vertretbare Entscheidung war. Heute würde ich denselben Stack mit TypeScript bauen – die zentrale Datenstruktur (Partnerschaftslinien mit ihren Metadaten) ist genau die Stelle, an der ein Typsystem die Iteration beschleunigt.

Komponentisierung. Filter-Steuerelemente, Popups und Legende leben als einzelne DOM-Funktionen im selben Skript. Eine kleine Komponentenstruktur – auch ohne Framework – würde die Wartung erleichtern, wenn jemand in zwei Jahren Filter-Kategorien ergänzen will.

Barrierefreiheit für die Karte selbst. Karten sind ein bekannter A11y-Stolperstein – die zentrale visuelle Information ist für Screenreader nahezu undurchsuchbar. Eine alternative Listendarstellung derselben Daten als Fallback hätte das Tool für mehr Nutzer:innen zugänglich gemacht.