Skip to content

KLXM/vector_maps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vector Maps – REDAXO AddOn

Interaktive Vektorkarten für REDAXO – datenschutzkonform, ohne API-Key, vollständig selbst


Features

  • Kein API-Key erforderlich – nutzt OpenFreeMap (freie Vektorkacheln)
  • DSGVO-konform – externer Datenverkehr wird vollständig über einen PHP-Proxy geleitet; Whitelist per Extension Point VECTOR_MAPS_PROXY_DOMAINS und Backend-Einstellungen erweiterbar
  • Web Component <vectormap> – direkt im Template oder Modul verwendbar, kein JavaScript nötig
  • Lazy-Init + Build-Queue – WebGL-Kontext wird sequentiell für jede Karte aufgebaut, erst wenn sie in den Viewport scrollt (verhindert Browserlimit von ~10 parallelen WebGL-Kontexten)
  • Backend-Koordinatenpicker – Koordinatenfelder in REDAXO-Modulen mit Karte und Adresssuche
  • Routing – Koordinaten oder Adressen, mit Auto-, Fuß- und Fahrradmodus (OSRM)
  • Interaktives Routenpanel – Von/Nach-Adressen direkt auf der Karte eingeben (Autocomplete); GPS-Locate-Button übernimmt den aktuellen Gerätestandort als Startpunkt
  • Umgebungssuche (nearby) – POI-Suche via Overpass API (z. B. Ladestationen, Restaurants)
  • Dynamisches Datennachladen – GeoJSON-Source per moveend aktualisieren (z. B. Ladestationen live aus OSM)
  • Freie Wetter-APIs – Open-Meteo und Bright Sky (DWD) via Proxy, kein API-Key, Badge-Marker mit Live-Daten
  • Standortsuche – optionale Geolokalisierung des Nutzers als Ausgangspunkt
  • Themesdark, warm, mono eingebaut, frei erweiterbar via Theme-Editor im Backend; Routing-Linienfarbe im Theme-Editor konfigurierbar; Themes werden per Fetch geladen und erst danach eingeblendet (kein Flash of Unstyled Map)
  • Theme-Fade-in – Karte blendet sich sanft ein sobald das Theme geladen ist; Dauer per theme-transition-Attribut (ms) steuerbar
  • 3D-Gebäude – aktivierbar per Attribut
  • Mehrsprachigkeit – Sprachcode per language-Attribut, steuert Kartenbeschriftungen von OpenFreeMap
  • Cluster – automatische Marker-Bündelung bei vielen Punkten
  • Satellitenbild – ESRI World Imagery als map-style="satellite" oder per show-satellite Toggle-Button, kein API-Key (Tiles laufen DSGVO-konform über den Proxy)
  • maxPitch 60° – Kamerakippung auf 60° begrenzt (verhindert extreme Perspektiven)

Installation

Über den REDAXO-Installer oder manuell:

  1. AddOn-Verzeichnis nach redaxo/src/addons/vector_maps/ kopieren
  2. Im REDAXO-Backend unter Installer > Eigene AddOns installieren und aktivieren

Keine weiteren Abhängigkeiten oder Node-Build-Schritte notwendig.


Frontend-Einbindung

Automatisch (Standard)

Nach der Installation lädt das AddOn alle benötigten Assets automatisch im Frontend — keine manuelle Einbindung notwendig. Die CSS- und JS-Dateien werden von REDAXO im <head> / vor </body> ausgegeben:

maplibre-gl.css        → MapLibre GL JS Kern-Styles
vectormaps.css         → Web Component Styles + Dark Mode
maplibre-gl.js         → MapLibre GL JS Kern-Script
vectormaps.js          → <vectormap> Custom Element

Danach kann <vectormap> direkt in jedem Template, Modul oder Artikel verwendet werden:

<!-- Karte einfach per Tag ausgeben – kein JS nötig -->
<vectormap lat="51.43" lng="6.77" zoom="13" height="400px"></vectormap>

Manuell (wenn Auto-Loading deaktiviert)

Über Vector Maps → Einstellungen kann das automatische Laden deaktiviert werden (load_frontend = false). In diesem Fall müssen die Assets im Template manuell eingebunden werden:

<?php
// In project/templates/template.php oder einem Fragment:
$vmAddon = rex_addon::get('vector_maps');
?>
<!DOCTYPE html>
<html>
<head>
    <!-- MapLibre GL JS Styles -->
    <link rel="stylesheet" href="<?= $vmAddon->getAssetsUrl('maplibre/maplibre-gl.css') ?>">
    <!-- Vector Maps Styles (Dark Mode, Custom Marker, Route-Panel …) -->
    <link rel="stylesheet" href="<?= $vmAddon->getAssetsUrl('build/vectormaps.css') ?>">
</head>
<body>

    <!-- Karten-Tags hier platzieren -->
    <vectormap lat="51.43" lng="6.77" zoom="13"></vectormap>

    <!-- MapLibre GL JS Core (defer empfohlen) -->
    <script defer src="<?= $vmAddon->getAssetsUrl('maplibre/maplibre-gl.js') ?>"></script>
    <!-- Vector Maps Web Component (defer empfohlen) -->
    <script defer src="<?= $vmAddon->getAssetsUrl('build/vectormaps.js') ?>"></script>
</body>
</html>

Hinweis: Die tatsächlichen Asset-Pfade variieren je nach REDAXO-Installation. getAssetsUrl() liefert immer die korrekte absolute URL.

Einbindung über REDAXO-Modul

Im Modul-Output kann die Karte direkt mit REX_VALUE-Platzhaltern ausgegeben werden:

<?php
// Module output
$lat = rex_escape(REX_VALUE[1]);
$lng = rex_escape(REX_VALUE[2]);
$zoom = rex_escape(REX_VALUE[3] ?: '14');
$popup = rex_escape(REX_VALUE[4]);
?>
<vectormap
    lat="<?= $lat ?>"
    lng="<?= $lng ?>"
    zoom="<?= $zoom ?>"
    height="400px"
    markers='[{"lat":<?= $lat ?>,"lng":<?= $lng ?>,"popup":"<?= $popup ?>"}]'>
</vectormap>

CSP-Hinweis (Content-Security-Policy)

Falls eine Content-Security-Policy aktiv ist, müssen folgende Direktiven ergänzt werden — nur für Seiten mit Karten:

worker-src blob:;

Alle Tile-Requests laufen über den REDAXO-Proxy (/?rex_api_vector_maps_proxy=1), daher sind keine externen connect-src-Einträge für OpenFreeMap, Nominatim oder OSRM notwendig.


<!-- Einfache Karte -->
<vectormap lat="51.51" lng="-0.12" zoom="12"></vectormap>

<!-- Mit Markern und Popup -->
<vectormap lat="51.51" lng="-0.12" zoom="13"
    markers='[{"lat":51.51,"lng":-0.12,"popup":"London"}]'>
</vectormap>

<!-- Vollbreite, 3D, Dark-Theme -->
<vectormap lat="48.85" lng="2.35" zoom="15"
    height="500px" theme="dark" 3d>
</vectormap>

Alle Attribute

Attribut Standard Beispiel Beschreibung
lat 51.505 lat="51.51" Breitengrad des Kartenzentrums
lng 7.0 lng="-0.12" Längengrad des Kartenzentrums
center center="51.51,-0.12" Kartenmitte als lat,lng (Alternative zu lat+lng)
zoom 6 zoom="15" Anfangszoomstufe (0–22)
height 400 height="600px" CSS-Höhe des Karten-Containers
pitch 0 pitch="45" Kamerakippung in Grad (0–60)
bearing 0 bearing="45" Kartenausrichtung in Grad
map-style liberty map-style="satellite" OFM-Stilname: liberty, bright, positron, satellite (ESRI World Imagery) – oder Theme-Name
show-satellite false show-satellite Toggle-Button zum Wechsel zwischen Vektor- und Satellitenbild (ESRI World Imagery, kein API-Key)
theme theme="dark" Farb-Theme: dark, warm, mono oder eigener Theme-Name
theme-transition 350 theme-transition="600" Einblend-Dauer in ms nach Theme-Load (0 = sofort, Standard: 350)
language de language="en" Sprachcode für Kartenbeschriftungen (ISO 639-1)
markers markers='[{"lat":51.51,"lng":-0.12}]' JSON-Array mit Marker-Objekten
fit-bounds auto fit-bounds="false" Kartenausschnitt an alle Marker anpassen. Standard: aktiv bei mehreren Markern; mit fit-bounds="false" deaktivieren
cluster false cluster Marker bei hoher Dichte clustern
3d false 3d 3D-Gebäude aktivieren
interactive true interactive="false" Karte scrollbar/zoombar (Standard: aktiv). Mit interactive="false" deaktivieren
locate false locate Standort-Button anzeigen
no-navigation false no-navigation Zoom-/Kompass-Controls ausblenden
no-attribution false no-attribution Attributionszeile ausblenden
fly-to fly-to="48.85,2.35" Kartenansicht nach dem Laden animiert zentrieren
min-zoom 0 min-zoom="5" Minimaler Zoom-Level
max-zoom 22 max-zoom="18" Maximaler Zoom-Level

Routing

Routen zwischen zwei Punkten berechnen – sowohl mit Koordinaten als auch mit Adressen. Alle Routing-Anfragen laufen über OSRM und werden DSGVO-konform über den PHP-Proxy geleitet.

<!-- Routing mit Koordinaten -->
<vectormap lat="51.43" lng="6.77" zoom="13"
    route-from="51.4298,6.7742"
    route-to="51.4539,6.7658"
    route-mode="walking">
</vectormap>

<!-- Routing mit Adressen -->
<vectormap lat="48.85" lng="2.35" zoom="6"
    route-from="Eiffelturm, Paris"
    route-to="Duisburg Hauptbahnhof"
    route-mode="driving">
</vectormap>

Routing-Attribute

Attribut Standard Beispiel Beschreibung
route-from route-from="51.43,6.77" Startpunkt: lat,lng oder Adresse als Text
route-to route-to="51.45,6.76" Zielpunkt: lat,lng oder Adresse als Text
route-mode driving route-mode="walking" Routing-Profil: driving, walking, cycling
route-panel false route-panel Interaktives Von/Nach-Panel auf der Karte einblenden
route-to-locked false route-to-locked Zieladresse im Panel fixieren – nicht editierbar, kein Autocomplete
route-to-popup route-to-popup="Firmenname<br>firmenname.de" Eigener Popup-Inhalt (HTML) am Ziel-Marker, wenn nur route-to gesetzt ist
route-no-steps false route-no-steps Abbiegehinweise (Turn-by-Turn) im Panel ausblenden

Interaktives Routenpanel (route-panel)

Das Routenpanel wird als schwebende Seitenleiste auf der Karte angezeigt und ermöglicht es, Start- und Zielpunkt direkt per Texteingabe (mit Autocomplete) sowie das Profil per Klick zu wählen:

<vectormap lat="51.43" lng="6.77" zoom="13"
    height="500px" interactive route-panel
    route-from="Duisburg Hauptbahnhof"
    route-to="Duisburg Innenstadt">
</vectormap>

Das Routenpanel zeigt SVG-Icons für die drei Modi Auto, Zu Fuß und Fahrrad. Es überschreibt route-from/route-to-Attribute nicht, sondern verwendet sie als Startwerte.

Fixiertes Ziel (route-to-locked)

Wenn das Ziel fest vorgegeben ist (z.B. ein Firmenstandort), kann das Zielfeld eingesperrt werden. Der Nutzer gibt nur seine Startadresse ein — das Ziel ist nicht editierbar und hat kein Autocomplete:

<vectormap lat="51.4298" lng="6.7742" zoom="12"
    height="450px"
    interactive
    route-panel
    route-to="Duisburg Hauptbahnhof"
    route-to-locked
    route-no-steps>
</vectormap>

Mit route-no-steps wird nur der berechnete Weg auf der Karte angezeigt — ohne Schritt-für-Schritt-Abbiegehinweise darunter. Ideal für Anfahrtskarten auf Kontaktseiten.

Anfahrtskarte mit Firmen-Marker (route-to-popup)

Wenn nur route-to gesetzt ist (kein route-from), wird das Ziel automatisch geocodiert, ein Marker gesetzt und die Karte zentriert. Mit route-to-popup kann der Popup-Inhalt des Markers frei definiert werden:

<vectormap
    height="500px"
    route-panel
    route-to="Am Schürmannshütt 40g, 47441 Moers"
    route-to-popup="<strong>KLXM Crossmedia GmbH</strong><br>klxm.de"
    route-to-locked
    route-mode="driving">
</vectormap>

Der Nutzer sieht sofort den Ziel-Marker mit Popup. Sobald er seine Startadresse eingibt, wird die Route berechnet.


Satellitenbild

Zwei Möglichkeiten, ESRI World Imagery (kostenlos, kein API-Key) zu nutzen:

<!-- Reines Satellitenbild -->
<vectormap lat="48.858844" lng="2.294351" zoom="16" height="400px"
    map-style="satellite">
    <marker lat="48.858844" lng="2.294351" popup="Eiffelturm"></marker>
</vectormap>

<!-- Vektor-Karte mit Toggle-Button für Satellitenansicht -->
<vectormap lat="52.520008" lng="13.404954" zoom="13" height="400px"
    show-satellite>
    <marker lat="52.520008" lng="13.404954" popup="Brandenburger Tor"></marker>
</vectormap>
Stil Beschreibung
satellite Reines Satellitenbild (ESRI World Imagery)
show-satellite Toggle-Button zum Wechsel zwischen aktuellem Vektorstil und Satellitenbild

Der show-satellite Toggle-Button erscheint unten rechts. Marker bleiben beim Wechsel erhalten, GeoJSON-Layer werden nach Rückkehr zur Vektorkarte automatisch neu geladen.

Hinweis: ESRI World Imagery und das Referenz-Overlay sind frei nutzbar (Lizenz: Esri Master License Agreement). Attribution wird automatisch gesetzt. Für gewerbliche Hochlast-Szenarien empfiehlt sich ein eigener Tile-Server.


Umgebungssuche (nearby)

Mit dem nearby-Attribut können Points of Interest (POI) aus OpenStreetMap rund um den Kartenmittelpunkt oder den Gerätestandort des Nutzers geladen werden. Die Abfragen laufen über die Overpass API und werden DSGVO-konform über den PHP-Proxy geleitet.

<!-- E-Ladestationen im Umkreis von 2 km um Duisburg HBF -->
<vectormap lat="51.4298" lng="6.7742" zoom="13"
    height="500px"
    nearby="amenity=charging_station"
    nearby-radius="2000"
    nearby-label="Ladestation">
</vectormap>

<!-- Supermärkte und Discounter in der Nähe des Nutzers -->
<vectormap lat="51.43" lng="6.77" zoom="13"
    height="500px"
    nearby="shop=supermarket|shop=discount"
    nearby-locate>
</vectormap>

Nearby-Attribute

Attribut Standard Beispiel Beschreibung
nearby nearby="amenity=restaurant" Overpass-Filter (key=value), mehrere mit | trennen
nearby-radius 1000 nearby-radius="2000" Suchradius in Metern
nearby-label OSM-Tags nearby-label="Restaurant" Fallback-Label für Popups (wenn kein OSM-Name)
nearby-locate false nearby-locate Nutzerstandort (Geolokalisierung) als Suchmittelpunkt verwenden

Häufige Overpass-Filter

Filter Beschreibung
amenity=charging_station E-Ladestationen
amenity=fuel Tankstellen
amenity=restaurant Restaurants
amenity=cafe Cafés
amenity=pharmacy Apotheken
amenity=hospital Krankenhäuser
amenity=bank Banken
shop=supermarket Supermärkte
shop=supermarket|shop=discount Supermärkte und Discounter
leisure=park Parks
tourism=hotel Hotels
tourism=museum Museen

Hinweis: Bei nearby-locate fragt die Karte den Browser nach dem Gerätestandort. Fällt die Geolokalisierung fehl, wird automatisch auf den Kartenmittelpunkt zurückgegriffen.


Dynamisches Datennachladen

Über die globale Hilfsfunktion vmProxyUrl() können externe APIs auch client-seitig per JavaScript angesprochen werden – DSGVO-konform über den REDAXO-Proxy, ohne CORS-Probleme.

Ladestationen live nachladen (Overpass API)

Das folgende Muster lädt E-Ladesäulen dynamisch für den aktuellen Kartenausschnitt, sobald die Karte bewegt wird:

// Zugriff auf die MapLibre-Instanz eines <vectormap>-Elements
const el  = document.getElementById('meine-karte');
const map = el._vmMap; // nach dem 'load'-Event verfügbar

// GeoJSON-Source + Layer anlegen
map.addSource('stationen', {
  type: 'geojson',
  data: { type: 'FeatureCollection', features: [] }
});
map.addLayer({
  id: 'stationen-punkte', type: 'circle', source: 'stationen',
  paint: { 'circle-color': '#27ae60', 'circle-stroke-color': '#fff', 'circle-stroke-width': 2 }
});

// Bei Kartenbewegung Daten nachladen (debounced)
let timer;
map.on('moveend', () => {
  clearTimeout(timer);
  timer = setTimeout(async () => {
    if (map.getZoom() < 9) return; // erst ab Zoom 9 laden
    const b = map.getBounds();
    const q = `[out:json][timeout:10];`
      + `node["amenity"="charging_station"]`
      + `(${b.getSouth()},${b.getWest()},${b.getNorth()},${b.getEast()});`
      + `out 200;`;
    const data = await fetch(vmProxyUrl(
      'https://overpass-api.de/api/interpreter?data=' + encodeURIComponent(q)
    )).then(r => r.json());
    const features = (data.elements || []).map(n => ({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [n.lon, n.lat] },
      properties: n.tags
    }));
    map.getSource('stationen').setData({ type: 'FeatureCollection', features });
  }, 600);
});

Hinweis: vmProxyUrl ist nach dem Laden von vectormaps.js global verfügbar. overpass-api.de ist bereits in der Proxy-Whitelist (lib/Proxy.php) eingetragen.

Wetter-Daten via Open-Meteo / Bright Sky (DWD)

// Aktuelles Wetter für Berlin via Open-Meteo
const omUrl = 'https://api.open-meteo.com/v1/forecast'
    + '?latitude=52.52&longitude=13.405&current=temperature_2m,weather_code&timezone=auto';
const omData = await fetch(vmProxyUrl(omUrl)).then(r => r.json());
console.log('Berlin:', omData.current.temperature_2m, '°C');

// Aktuelles DWD-Wetter für Hamburg via Bright Sky
const bsUrl = 'https://api.brightsky.dev/current_weather?lat=53.55&lon=10.0';
const bsData = await fetch(vmProxyUrl(bsUrl)).then(r => r.json());
console.log('Hamburg:', bsData.weather.temperature, '°C', bsData.weather.condition);

Beide Dienste sind bereits in der Proxy-Whitelist eingetragen (api.open-meteo.com, api.brightsky.dev).


Themes

Drei eingebaute Themes stehen sofort zur Verfügung:

Theme Attribut Beschreibung
Standard (leer) Helles Standardlayout (OpenFreeMap Liberty)
dark theme="dark" Dunkles Layout
warm theme="warm" Warmes Orange-/Beigelayout
mono theme="mono" Graustufen-Layout

Eigene Themes können im Backend unter Vector Maps → Themes angelegt und live per Theme-Editor konfiguriert werden. Die Routing-Linienfarbe (route_line) lässt sich ebenfalls pro Theme einstellen.

Theme-Fade-in

Bei Karten mit einem Theme (theme="..." oder map-style="<eigener-name>") bleibt die Karte zunächst unsichtbar und blendet sich sanft ein, sobald das Theme vollständig geladen und angewendet wurde. Das verhindert das kurze Aufblitzen des ungestylten Grundstils ("Flash of Unstyled Map").

Die Einblend-Dauer ist per Attribut steuerbar:

<!-- Standard: 350 ms -->
<vectormap map-style="klxm" height="400px"></vectormap>

<!-- Langsam: 800 ms -->
<vectormap map-style="klxm" theme-transition="800" height="400px"></vectormap>

<!-- Sofort (kein Fade): 0 ms -->
<vectormap map-style="klxm" theme-transition="0" height="400px"></vectormap>

Marker-Format

Marker werden als JSON-Array übergeben:

<vectormap lat="51.43" lng="6.77" zoom="12"
    markers='[
        {"lat":51.4298,"lng":6.7742,"popup":"<strong>Duisburg HBF</strong>"},
        {"lat":51.4539,"lng":6.7658,"popup":"Duisburg Zoo","color":"#e74c3c"}
    ]'>
</vectormap>

Unterstützte Marker-Eigenschaften:

Eigenschaft Beschreibung
lat, lng Position (erforderlich)
popup Popup-Inhalt (HTML erlaubt)
color Marker-Farbe für Standard-Pin (CSS-Farbwert, Standard: #2b7095)
icon URL zu einem Bild (PNG, SVG, WebP) → Custom-Pin als <img>
html Beliebiger HTML-String, Emoji oder SVG → Custom-Pin als HTML-Element
size [breite, höhe] in px für icon-Marker, z. B. [40, 48] (Standard: 32×32)
anchor Ankerpunkt des Custom-Pins: bottom (Standard), center, top, left, right

Custom Pins / Individuelle Marker

Jeder Marker kann als individueller Pin gestaltet werden – per Emoji, SVG, HTML-Div oder externem Bild:

<!-- Emoji-Pins -->
<vectormap lat="51.43" lng="6.77" zoom="13"
    markers='[
        {"lat":51.4298,"lng":6.7742,"html":"🚉","anchor":"center","popup":"Bahnhof"},
        {"lat":51.4339,"lng":6.7621,"html":"🏛️","anchor":"center","popup":"Museum"},
        {"lat":51.4218,"lng":6.7660,"html":"🏬","anchor":"center","popup":"Einkauf"}
    ]'>
</vectormap>

<!-- HTML-Div-Pins mit eigenem CSS -->
<vectormap lat="51.43" lng="6.77" zoom="13"
    markers='[
        {"lat":51.4298,"lng":6.7742,
         "html":"<div class=\"mein-pin mein-pin--rot\">A</div>",
         "popup":"Punkt A"}
    ]'>
</vectormap>

<!-- Icon-URL (SVG/PNG) mit benutzerdefinierter Größe -->
<vectormap lat="51.43" lng="6.77" zoom="13"
    markers='[
        {"lat":51.4298,"lng":6.7742,
         "icon":"/assets/custom/pin.svg",
         "size":[40,48],
         "anchor":"bottom",
         "popup":"Unser Standort"}
    ]'>
</vectormap>

Custom-Marker (icon / html) nutzen intern MapLibres element-Option und sind vollständig per CSS gestaltbar. Im Cluster-Modus werden sie als Standard-GeoJSON-Punkte dargestellt.


Externes GeoJSON

Mit dem geojson-Attribut können externe oder inline GeoJSON-Daten direkt auf der Karte angezeigt werden. Unterstützt werden Punkte, Linien und Flächen (auch gemischt in einer FeatureCollection).

<!-- Relative URL (wird direkt geladen) -->
<vectormap lat="51.43" lng="6.77" zoom="10"
    geojson="/assets/karte-data.geojson"
    geojson-color="#27ae60"
    geojson-popup="name">
</vectormap>

<!-- Externe URL (wird automatisch über den REDAXO-Proxy geleitet) -->
<vectormap lat="51.43" lng="6.77" zoom="6"
    geojson="https://example.com/data.geojson"
    geojson-color="#e74c3c"
    geojson-opacity="0.4"
    geojson-popup="description">
</vectormap>

<!-- Inline-JSON (kein Server-Request) -->
<vectormap lat="51.434" lng="6.763" zoom="14"
    geojson='{"type":"FeatureCollection","features":[
        {"type":"Feature","properties":{"name":"Innenhafen"},"geometry":{"type":"Polygon","coordinates":[...]}},
        {"type":"Feature","properties":{"name":"Museum"},"geometry":{"type":"Point","coordinates":[6.762,51.434]}}
    ]}'
    geojson-color="#2980b9"
    geojson-opacity="0.25">
</vectormap>

GeoJSON-Attribute

Attribut Standard Beispiel Beschreibung
geojson geojson="/data.geojson" Relative/absolute URL oder Inline-JSON-String
geojson-color #2b7095 geojson-color="#e74c3c" Standardfarbe für Punkte, Linien und Flächen
geojson-opacity 0.3 geojson-opacity="0.5" Transparenz der Flächen-Füllung (0–1)
geojson-popup (alle) geojson-popup="name" Property-Name für Klick-Popup; leer = automatische Tabelle aller Properties

geojson und markers lassen sich kombinieren — GeoJSON-Layer und individuelle Marker erscheinen gleichzeitig auf der Karte.

Individuelle Marker-Pins via GeoJSON (Simplestyle)

Punkte können pro Feature individuell gestaltet werden — direkt über GeoJSON-Properties ohne zusätzliche Attribute:

<vectormap lat="51.434" lng="6.763" zoom="13"
    geojson='{
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "properties": {
                    "name": "Ladestation",
                    "Betreiber": "Stadtwerke",
                    "marker-color": "#27ae60",
                    "marker-symbol": "⚡"
                },
                "geometry": { "type": "Point", "coordinates": [6.763, 51.434] }
            },
            {
                "type": "Feature",
                "properties": {
                    "name": "Museum",
                    "marker-color": "#8e44ad",
                    "marker-symbol": "🏛"
                },
                "geometry": { "type": "Point", "coordinates": [6.770, 51.430] }
            },
            {
                "type": "Feature",
                "properties": { "name": "Stadtpark" },
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[[6.760, 51.435],[6.780, 51.435],[6.780, 51.425],[6.760, 51.425],[6.760, 51.435]]]
                }
            }
        ]
    }'
    geojson-color="#2980b9"
    geojson-opacity="0.25"
    geojson-popup="name">
</vectormap>

Simplestyle-Properties (pro GeoJSON-Feature, nur für Punkte):

Property Beispiel Beschreibung
marker-color "#e74c3c" Pin-Farbe — überschreibt geojson-color für diesen Punkt
marker-symbol "⚡" "🏥" "A" Emoji oder Text-Zeichen im Pin. Ohne Angabe: Standard-Farb-Pin

Flächen und Linien nutzen weiterhin geojson-color und geojson-opacity global.

In PHP lässt sich das komfortabel mit json_encode() aufbauen:

$locations = [
    ['name' => 'Rathaus',    'lat' => 51.434, 'lng' => 6.762, 'symbol' => '🏛', 'color' => '#8e44ad'],
    ['name' => 'Ladestation','lat' => 51.437, 'lng' => 6.770, 'symbol' => '', 'color' => '#27ae60'],
    ['name' => 'Parkplatz',  'lat' => 51.431, 'lng' => 6.758, 'symbol' => '🅿', 'color' => '#2980b9'],
];

$features = array_map(static function(array $loc): array {
    return [
        'type'       => 'Feature',
        'properties' => [
            'name'          => $loc['name'],
            'marker-color'  => $loc['color'],
            'marker-symbol' => $loc['symbol'],
        ],
        'geometry' => [
            'type'        => 'Point',
            'coordinates' => [$loc['lng'], $loc['lat']],
        ],
    ];
}, $locations);

$geoJson = json_encode(['type' => 'FeatureCollection', 'features' => $features]);

echo '<vectormap lat="51.434" lng="6.763" zoom="13"'
   . ' geojson=\'' . rex_escape($geoJson) . '\''
   . ' geojson-popup="name">'
   . '</vectormap>';

Backend-Koordinatenpicker

Für REDAXO-Module kann ein Koordinatenpicker aktiviert werden, der ein einfaches Eingabefeld mit Kartenpicker-Button ausstattet.

Im Modul-Input

<div class="form-group">
    <label>Koordinaten</label>
    <input type="text"
        name="REX_INPUT_VALUE[1]"
        value="REX_VALUE[1]"
        class="form-control"
        data-vector-picker="1"
        placeholder="lat,lng">
</div>

Durch data-vector-picker="1" erscheint neben dem Feld ein Karten-Button. Beim Klick öffnet sich ein Modal mit einer Vollbild-Karte, Adresssuche (Autocomplete via Nominatim) und Koordinatenübernahme per Klick oder Suche.

Im Modul-Output

<vectormap lat="REX_VALUE[1]" lng="REX_VALUE[2]" zoom="14"
    markers='[{"lat":REX_VALUE[1],"lng":REX_VALUE[2],"popup":"Unser Standort"}]'>
</vectormap>

Alternativ: lat,lng aus einem einzelnen Feld parsen:

<?php
$coords = explode(',', 'REX_VALUE[1]');
$lat = trim($coords[0] ?? '51.5');
$lng = trim($coords[1] ?? '7.0');
?>
<vectormap lat="<?= $lat ?>" lng="<?= $lng ?>" zoom="14"></vectormap>

Proxy-Architektur (DSGVO)

Alle externen Dienste werden über den internen PHP-Proxy geleitet, sodass keine IP-Adressen der Websitebesucher an Dritte übertragen werden:

Dienst Verwendung
OpenFreeMap Vektorkacheln (Karte)
Nominatim / OpenStreetMap Adresssuche (Geocoding)
OSRM Routing (Fahrt-, Fuß-, Radwege)
Overpass API POI-Suche & dynamisches Datennachladen
Open-Meteo Weltweite Wettervorhersage (kostenlos, kein API-Key)
Bright Sky / DWD Deutsche Wetterdaten (DWD Open Data, Server in DE)
Esri ArcGIS / World Imagery Satellitenbilder (Raster-Tiles)

Der Proxy unter lib/Proxy.php validiert alle Anfragen gegen eine Whitelist und leitet nur Anfragen an erlaubte Domains weiter. SSRF-Attacks werden durch strikte Domain-Prüfung verhindert.

Whitelist erweitern

Per Extension Point (andere AddOns):

rex_extension::register('VECTOR_MAPS_PROXY_DOMAINS', static function(rex_extension_point $ep): array {
    $list = $ep->getSubject();
    $list[] = 'https://my-tiles.example.com/';
    return $list;
});

Per Backend-Einstellungen (manuell): Unter Vector Maps → Einstellungen → Proxy: Zusätzliche erlaubte Domains können URL-Präfixe (eine pro Zeile) hinterlegt werden.


Vollständiges Beispiel

<vectormap
    lat="51.4298"
    lng="6.7742"
    zoom="14"
    height="500px"
    theme="dark"
    3d
    interactive
    locate
    markers='[
        {"lat":51.4298,"lng":6.7742,"popup":"<strong>Duisburg Hauptbahnhof</strong><br>Bahnhofsvorplatz, 47119 Duisburg","color":"#3498db"}
    ]'
    route-from="51.4298,6.7742"
    route-to="51.4539,6.7658"
    route-mode="walking">
</vectormap>

Backend-Seiten

Seite Beschreibung
Demo Interaktive Übersicht aller Features mit Live-Beispielen
Themes Theme-Editor zum Erstellen und Anpassen benutzerdefinierter Themes (inkl. Routing-Linienfarbe)
Einstellungen Frontend-Einbindung, Proxy-Whitelist (manuelle Domains), Tile-Cache verwalten

Voraussetzungen

  • REDAXO >= 5.14
  • PHP >= 8.1
  • PHP-Extensions: curl, json

Build-System (Entwicklung)

Der build/-Ordner enthält das Build-Tooling für Entwickler. Für den normalen Einsatz des AddOns wird kein Build-Schritt benötigt — alle kompilierten Assets liegen bereits fertig im Repository.

Ordnerstruktur

vector_maps/
├── assets/
│   ├── build/                   # Eigene Assets (Quelle + kompiliert)
│   │   ├── vectormaps.js        # Quelle: <vectormap> Web Component + Picker
│   │   ├── vectormaps.min.js    # Minifiziert (vom Build generiert)
│   │   ├── vectormaps_i18n.js   # Quelle: Frontend-Übersetzungen
│   │   ├── vectormaps_i18n.min.js
│   │   ├── theme-editor.js      # Quelle: Backend Theme-Editor
│   │   ├── theme-editor.min.js
│   │   ├── vectormaps.css       # Quelle: Styles
│   │   └── vectormaps.min.css   # Minifiziert (vom Build generiert)
│   └── maplibre/                # Vendor-Assets (von npm kopiert)
│       ├── maplibre-gl.js       # MapLibre GL JS
│       ├── maplibre-gl.css      # MapLibre GL JS Styles
│       └── pmtiles.js           # PMTiles-Decoder
├── build/                       # Build-Tooling (nicht im Release-ZIP)
│   ├── package.json             # npm-Abhängigkeiten (esbuild, maplibre-gl, pmtiles)
│   └── build.mjs                # Build-Script
└── .github/
    └── workflows/
        └── release.yml          # GitHub Actions: Release-ZIP auf Tag-Push

build/node_modules/ und *.map-Dateien sind per .gitignore ausgeschlossen und landen nicht im Release-ZIP.

Voraussetzungen

  • Node.js >= 18
  • npm

Setup

cd vector_maps/build
npm install

Befehle

Befehl Beschreibung
npm run build Eigene Assets (assets/build/) minifizieren
npm run build:all Vendor-Assets aus npm aktualisieren und eigene Assets minifizieren
npm run watch Watch-Modus: automatisch neu bauen bei Dateiänderungen (+ Source Maps)

Eigene Assets minifizieren

cd build
npm run build

Erzeugt *.min.js / *.min.css aus den Quelldateien in assets/build/.

Vendor-Assets aktualisieren (z. B. neues MapLibre-Release)

cd build
npm install                 # package.json aktualisieren falls nötig
npm run build:all

Kopiert die Distributionsdateien aus node_modules/maplibre-gl/dist/ und node_modules/pmtiles/dist/ nach assets/maplibre/ und baut anschließend alle eigenen Assets.

Watch-Modus (Entwicklung)

cd build
npm run watch

Überwacht alle Quelldateien in assets/build/ und kompiliert auf Änderungen sofort neu. Im Watch-Modus werden zusätzlich Source Maps (.map) generiert — sie sind per .gitignore ausgeschlossen und landen nicht im Repository.

Release

Releases werden automatisch per GitHub Actions erstellt, wenn ein Tag (v*.*.*) gepusht wird:

git tag v1.1.0
git push origin v1.1.0

Der Workflow (release.yml) installiert npm-Abhängigkeiten, baut alle Assets (npm run build:all) und erstellt ein Release-ZIP ohne den build/-Ordner, node_modules, .map-Dateien und andere Dev-Artefakte.


Credits

  • MapLibre GL JS – Open-Source-Kartenbibliothek (BSD-2-Clause)
  • OpenFreeMap – Kostenlose Vektorkacheln ohne API-Key
  • Nominatim / OSM – Adress-Geocoding (ODbL)
  • OSRM – Open Source Routing Machine (BSD-2-Clause)
  • Overpass API – OSM-Datenbankabfragen (AGPL)
  • Open-Meteo – Kostenlose Wetter-API, kein API-Key (CC BY 4.0)
  • Bright Sky – DWD-Wetterdaten für Deutschland (CC BY 4.0)

Lizenz

MIT License – siehe LICENSE.md

Entwickelt von KLXM Crossmedia

About

REDAXO AddOn Vector Maps :: MapLibre GL JS OpenFreeMap

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors