WikiMap: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) Die Seite wurde neu angelegt: „Hauptseite > Schwarzatal.org == Technische Dokumentation: Kartenprojekt (WikiMap) == Das Kartenprojekt bindet interaktive [https://leafletjs.com Leaflet]-Karten in Wiki-Seiten ein. Diese Dokumentation erklärt alle beteiligten Dateien, ihren Speicherort und ihre Funktion. === Die zwei Speicherorte === Das Projekt lebt an zwei getrennten Orten. Diese nicht zu verwechseln ist wichtig: * '''Server (FTP)''' unter <code>…“ |
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| (9 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 58: | Zeile 58: | ||
|- | |- | ||
| <code>MediaWiki:WikiMap-Orte.json</code> || '''Zentrale Datenquelle für alle | | <code>MediaWiki:WikiMap-Orte.json</code> || '''Zentrale Datenquelle für alle | ||
Stecknadeln.''' Jeder Ort steht hier genau einmal | Stecknadeln.''' Jeder Ort steht hier genau einmal. Enthält außerdem die | ||
Farbzuordnung der Kategorien. Kernidee: eine Stelle für alle Pins, überall im | |||
Wiki automatisch aktuell. | Wiki automatisch aktuell. | ||
|- | |- | ||
| Zeile 76: | Zeile 76: | ||
<pre> | <pre> | ||
<div class="wikimap" data-aktiv-ort=" | <div class="wikimap" data-aktiv-ort="Ternitz Bahnhof"></div> | ||
</pre> | </pre> | ||
| Zeile 82: | Zeile 82: | ||
Das <code>data-aktiv-ort</code> nennt die ID des hervorgehobenen Ortes. Die | Das <code>data-aktiv-ort</code> nennt die ID des hervorgehobenen Ortes. Die | ||
Karte holt sich Position und alle anderen Pins selbst aus der zentralen JSON. | Karte holt sich Position und alle anderen Pins selbst aus der zentralen JSON. | ||
Alle verfügbaren Attribute: | |||
{| class="wikitable" | |||
! Attribut !! Wirkung | |||
|- | |||
| <code>data-aktiv-ort</code> || ID des hervorgehobenen Ortes (rot, | |||
pulsierend, zentriert, Popup offen) | |||
|- | |||
| <code>data-filter</code> || Nur Orte bestimmter Kategorien zeigen; mehrere | |||
kommagetrennt möglich | |||
|- | |||
| <code>data-gemeinden="ja"</code> || Gemeinde-Umrisse einblenden | |||
|- | |||
| <code>data-hoehe</code> || Kartenhöhe in Pixeln (sonst CSS-Standard) | |||
|} | |||
=== Orte anlegen: die Felder === | |||
Jeder Ort in <code>MediaWiki:WikiMap-Orte.json</code> besteht aus wenigen | |||
Feldern. Die <code>id</code> ist zugleich Anzeigename und Ziel-Wikiseite – | |||
die Regel lautet: '''Ort heißt wie seine Wiki-Seite.''' | |||
{| class="wikitable" | |||
! Feld !! Pflicht? !! Bedeutung | |||
|- | |||
| <code>id</code> || ja || Eindeutiger Name. Erscheint im Popup und ist | |||
zugleich die Ziel-Wikiseite beim Klick. | |||
|- | |||
| <code>geo</code> || ja* || Koordinaten als Text <code>"lat,lon"</code> – | |||
direkt aus OSM.org oder OrganicMaps kopierbar. Beispiel: | |||
<code>"47.7073509,15.9933643"</code> | |||
|- | |||
| <code>lat</code> / <code>lon</code> || ja* || Alternative zu | |||
<code>geo</code>: Koordinaten als zwei Zahlenfelder. | |||
|- | |||
| <code>kategorie</code> || nein || Für Filter und Pin-Farben. | |||
|- | |||
| <code>seite</code> || nein || Übersteuert das Klick-Ziel: ein anderer | |||
Wiki-Seitenname '''oder''' eine externe Adresse (beginnend mit | |||
<code><nowiki>https://</nowiki></code>). Externe Links öffnen in neuem Tab. | |||
|} | |||
<nowiki>*</nowiki> Entweder <code>geo</code> oder <code>lat</code>+<code>lon</code> | |||
muss vorhanden sein. Sind beide da, gewinnt <code>geo</code>. | |||
Ein Ort im Normalfall – drei Felder genügen: | |||
<pre> | |||
{ | |||
"id": "Ternitz Bahnhof", | |||
"geo": "47.7073509,15.9933643", | |||
"kategorie": "bahnhof" | |||
} | |||
</pre> | |||
Ein Ort mit externer Website statt Wiki-Seite: | |||
<pre> | |||
{ | |||
"id": "Dr. Mustermann", | |||
"geo": "47.7,16.0", | |||
"kategorie": "hausarzt", | |||
"seite": "https://praxis-mustermann.at" | |||
} | |||
</pre> | |||
'''Fehlerverhalten:''' Ist das <code>geo</code>-Feld fehlerhaft (z.B. | |||
Tippfehler, Buchstaben statt Zahlen), wird der Ort nicht angezeigt. Der | |||
fehlende Pin fällt auf – dann in der JSON nachsehen. | |||
=== Ablauf beim Seitenaufruf === | === Ablauf beim Seitenaufruf === | ||
| Zeile 102: | Zeile 172: | ||
die Karte aus. | die Karte aus. | ||
# Die '''Gadgets-Definition''' ist der Schalter, der das Ganze aktiviert. | # Die '''Gadgets-Definition''' ist der Schalter, der das Ganze aktiviert. | ||
<br><br><br><br> | |||
== Gemeinde-Umrisse == | |||
Zusätzlich zu den Stecknadeln kann die Karte die '''Umrisse von Gemeinden''' | |||
anzeigen. Klickt man auf einen Umriss, springt man zur jeweiligen | |||
Gemeinde-Wikiseite. Diese Funktion ist offen angelegt – es können laufend neue | |||
Gemeinden ergänzt werden. | |||
=== Wie es technisch funktioniert === | |||
Eine Gemeindegrenze ist eine Kette aus tausenden Koordinaten-Punkten, die | |||
zusammen den Umriss ergeben. Diese Umrisse liegen gebündelt in der Wiki-Seite | |||
<code>MediaWiki:WikiMap-Gemeinden.json</code> im sogenannten | |||
[https://de.wikipedia.org/wiki/GeoJSON GeoJSON]-Format. | |||
Jede Gemeinde ist dort ein „Feature" mit zwei Teilen: | |||
* '''Geometrie''' – die Koordinatenkette des Umrisses | |||
* '''Eigenschaften''' – <code>name</code> (Anzeigename) und <code>seite</code> | |||
(Ziel-Wikiseite beim Klick) | |||
Damit eine Karte die Umrisse zeigt, muss das Element auf der Seite das Attribut | |||
<code>data-gemeinden="ja"</code> tragen: | |||
<pre> | |||
<div class="wikimap" data-gemeinden="ja"></div> | |||
</pre> | |||
=== Eine neue Gemeinde hinzufügen === | |||
Der Vorgang besteht aus zwei Schritten: erst die Umrisse von OpenStreetMap | |||
holen, dann mit dem Skript zur fertigen Datei zusammenbauen. | |||
==== Schritt 1: Umriss von OpenStreetMap holen ==== | |||
# Die Gemeinde auf [https://www.openstreetmap.org OpenStreetMap] suchen und die | |||
'''Relation-ID''' der Gemeindegrenze herausfinden (z.B. über die Suche oder die | |||
Detailansicht der Grenze). | |||
# Den Umriss als GeoJSON beziehen. Zwei bewährte Wege: | |||
#* [https://polygons.openstreetmap.fr polygons.openstreetmap.fr] – Relation-ID | |||
eingeben, GeoJSON herunterladen. '''Einfachster Weg.''' | |||
#* Alternativ: <code><nowiki>https://www.openstreetmap.org/api/0.6/relation/ID/full</nowiki></code> | |||
aufrufen (das <code>/full</code> am Ende lädt die Koordinaten mit!) und die | |||
XML-Datei durch [https://tyrasd.github.io/osmtogeojson/ osmtogeojson] in GeoJSON | |||
umwandeln. | |||
# '''Wichtig:''' Eine XML ohne <code>/full</code> enthält keine Koordinaten und | |||
ist unbrauchbar. | |||
==== Schritt 2: Datei richtig benennen ==== | |||
Die GeoJSON-Datei MUSS exakt so heißen wie die Gemeinde '''und''' die | |||
zugehörige Wiki-Seite. Erster Buchstabe groß, Endung <code>.geojson</code>: | |||
* Gemeinde „Ternitz", Wiki-Seite „Ternitz" → Datei <code>Ternitz.geojson</code> | |||
* Gemeinde „Altendorf", Wiki-Seite „Altendorf" → Datei <code>Altendorf.geojson</code> | |||
Der Dateiname bestimmt automatisch den Anzeigenamen und das Klick-Ziel. Stimmt | |||
er nicht mit der Wiki-Seite überein, führt der Klick ins Leere. | |||
==== Schritt 3: Zusammenbauen mit dem Skript ==== | |||
# Alle Gemeinde-Dateien in einen Ordner namens <code>gemeinden</code> legen. | |||
# Das Skript <code>gemeinden-bauen.py</code> (siehe unten) daneben legen. | |||
# Ausführen: <code>python3 gemeinden-bauen.py</code> (unter Windows: | |||
<code>py gemeinden-bauen.py</code>) | |||
# Es entsteht die Datei <code>WikiMap-Gemeinden.json</code>. | |||
# Deren '''kompletten Inhalt''' in die Wiki-Seite | |||
<code>MediaWiki:WikiMap-Gemeinden.json</code> kopieren und speichern. | |||
Das Skript verarbeitet immer ''alle'' Dateien im Ordner. Zum Ergänzen also | |||
einfach die neue Datei dazulegen und das Skript erneut laufen lassen – die | |||
bestehenden Gemeinden bleiben erhalten. | |||
=== Das Skript: gemeinden-bauen.py === | |||
<pre> | |||
#!/usr/bin/env python3 | |||
# -*- coding: utf-8 -*- | |||
""" | |||
gemeinden-bauen.py | |||
============================================================================== | |||
Baut aus einzelnen Gemeinde-GeoJSON-Dateien EINE WikiMap-Gemeinden.json, | |||
die das WikiMap-Gadget einlesen kann. | |||
WIE BENUTZEN | |||
------------ | |||
1. Lege fuer jede Gemeinde eine GeoJSON-Datei in den Ordner "gemeinden". | |||
Der Dateiname MUSS dem Gemeinde- und Wiki-Seitennamen entsprechen: | |||
Ternitz.geojson -> Gemeinde "Ternitz", Wiki-Seite "Ternitz" | |||
Altendorf.geojson -> Gemeinde "Altendorf", Wiki-Seite "Altendorf" | |||
(Endung .geojson oder .json. Umlaute im Namen sind erlaubt.) | |||
2. Skript ausfuehren: | |||
python3 gemeinden-bauen.py | |||
3. Es entsteht die Datei "WikiMap-Gemeinden.json". Deren kompletten Inhalt | |||
in die Wiki-Seite MediaWiki:WikiMap-Gemeinden.json kopieren. | |||
WAS DAS SKRIPT MACHT | |||
-------------------- | |||
Jede Einzeldatei enthaelt nur nackte Geometrie (type + coordinates). | |||
Das Gadget braucht aber pro Gemeinde zusaetzlich "name" und "seite". | |||
Das Skript verpackt deshalb jede Geometrie in ein GeoJSON-"Feature" mit | |||
diesen Eigenschaften und fuegt alle zu einer FeatureCollection zusammen. | |||
Der Gemeindename wird aus dem Dateinamen abgeleitet (ohne Endung). | |||
name und seite werden gleich gesetzt (Wiki-Seite = Gemeindename). | |||
============================================================================== | |||
""" | |||
import json | |||
import os | |||
import sys | |||
# Ordner, in dem die einzelnen Gemeinde-Dateien liegen. | |||
QUELL_ORDNER = "gemeinden" | |||
# Name der Ausgabedatei. | |||
ZIEL_DATEI = "WikiMap-Gemeinden.json" | |||
def lade_geometrie(pfad): | |||
"""Liest eine GeoJSON-Datei und gibt deren Geometrie zurueck. | |||
Akzeptiert zwei Formen: | |||
a) Nackte Geometrie: {"type": "MultiPolygon", "coordinates": [...]} | |||
b) Bereits ein Feature: {"type": "Feature", "geometry": {...}, ...} | |||
In beiden Faellen wird das Geometrie-Objekt zurueckgegeben. | |||
""" | |||
with open(pfad, "r", encoding="utf-8") as f: | |||
daten = json.load(f) | |||
typ = daten.get("type") | |||
if typ in ("Polygon", "MultiPolygon", "GeometryCollection"): | |||
# Form a) nackte Geometrie | |||
return daten | |||
if typ == "Feature": | |||
# Form b) bereits ein Feature -> nur die Geometrie nehmen | |||
return daten.get("geometry") | |||
if typ == "FeatureCollection": | |||
# Ungewoehnlich: eine Sammlung in einer Einzeldatei. | |||
# Wir nehmen die erste Geometrie. | |||
feats = daten.get("features", []) | |||
if feats: | |||
return feats[0].get("geometry") | |||
raise ValueError("FeatureCollection ohne features") | |||
raise ValueError("Unbekannter GeoJSON-Typ: %r" % typ) | |||
def main(): | |||
if not os.path.isdir(QUELL_ORDNER): | |||
print("FEHLER: Ordner '%s' existiert nicht." % QUELL_ORDNER) | |||
print("Lege ihn an und lege die Gemeinde-GeoJSON-Dateien hinein.") | |||
sys.exit(1) | |||
features = [] | |||
dateien = sorted(os.listdir(QUELL_ORDNER)) | |||
verarbeitet = 0 | |||
for dateiname in dateien: | |||
if not (dateiname.endswith(".geojson") or dateiname.endswith(".json")): | |||
continue | |||
# Gemeindename = Dateiname ohne Endung. | |||
name = os.path.splitext(dateiname)[0] | |||
pfad = os.path.join(QUELL_ORDNER, dateiname) | |||
try: | |||
geometrie = lade_geometrie(pfad) | |||
except Exception as e: | |||
print(" UEBERSPRUNGEN: %s (%s)" % (dateiname, e)) | |||
continue | |||
if not geometrie: | |||
print(" UEBERSPRUNGEN: %s (keine Geometrie gefunden)" % dateiname) | |||
continue | |||
features.append({ | |||
"type": "Feature", | |||
"properties": { | |||
"name": name, | |||
"seite": name | |||
}, | |||
"geometry": geometrie | |||
}) | |||
verarbeitet += 1 | |||
print(" + %s" % name) | |||
if not features: | |||
print("FEHLER: Keine gueltigen GeoJSON-Dateien gefunden.") | |||
sys.exit(1) | |||
sammlung = { | |||
"type": "FeatureCollection", | |||
"features": features | |||
} | |||
with open(ZIEL_DATEI, "w", encoding="utf-8") as f: | |||
json.dump(sammlung, f, ensure_ascii=False, separators=(",", ":")) | |||
print("") | |||
print("Fertig: %d Gemeinde(n) in '%s' geschrieben." % (verarbeitet, ZIEL_DATEI)) | |||
print("Inhalt dieser Datei in MediaWiki:WikiMap-Gemeinden.json kopieren.") | |||
if __name__ == "__main__": | |||
main() | |||
</pre> | |||
=== Format der fertigen Datei === | |||
Zur Veranschaulichung – so sieht eine fertige <code>WikiMap-Gemeinden.json</code> | |||
mit zwei Gemeinden im Aufbau aus (Koordinaten gekürzt): | |||
<pre> | |||
{ | |||
"type": "FeatureCollection", | |||
"features": [ | |||
{ | |||
"type": "Feature", | |||
"properties": { "name": "Altendorf", "seite": "Altendorf" }, | |||
"geometry": { "type": "MultiPolygon", "coordinates": [ ... ] } | |||
}, | |||
{ | |||
"type": "Feature", | |||
"properties": { "name": "Ternitz", "seite": "Ternitz" }, | |||
"geometry": { "type": "MultiPolygon", "coordinates": [ ... ] } | |||
} | |||
] | |||
} | |||
</pre> | |||
=== Tipp: große Dateien === | |||
Detaillierte Umrisse können sehr groß werden. Wird die Karte dadurch träge, | |||
lassen sich die Polygone vorab vereinfachen – z.B. mit der „Simplify"-Funktion | |||
auf [https://mapshaper.org mapshaper.org] oder direkt beim Export auf | |||
polygons.openstreetmap.fr. Eine leichte Vereinfachung verkleinert die Datei | |||
deutlich, ohne dass die Umrisse sichtbar eckig werden. | |||
<br><br><br><br> | |||
== Kategorien, Filter und Farben == | |||
Jeder Ort kann eine <code>kategorie</code> haben. Kategorien haben zwei | |||
Funktionen: Sie steuern, '''welche Orte''' auf einer Karte erscheinen | |||
(Filter), und '''welche Farbe''' die Pins haben (Farbzuordnung). | |||
=== Kategorie einem Ort zuweisen === | |||
In der Orte-Datei bekommt ein Eintrag eine <code>kategorie</code>. Beispiel: | |||
<pre> | |||
{ | |||
"id": "Dr. Mustermann", | |||
"geo": "47.7,16.0", | |||
"kategorie": "hausarzt" | |||
} | |||
</pre> | |||
Alle Orte mit derselben Kategorie gehören zur selben Gruppe. Man kann beliebige | |||
Kategorien erfinden – etwa <code>hausarzt</code>, <code>bahnhof</code>, | |||
<code>wasserfall</code>, <code>gasthaus</code>. | |||
=== Nur eine Kategorie auf einer Karte zeigen === | |||
Auf einer Themenseite (z.B. „Hausärzte") bindet man die Karte mit dem Attribut | |||
<code>data-filter</code> ein: | |||
<pre> | |||
<div class="wikimap" data-filter="hausarzt"></div> | |||
</pre> | |||
Die Karte zeigt dann '''nur''' die Pins mit der Kategorie <code>hausarzt</code>. | |||
Alle anderen Orte (Bahnhöfe, Wasserfälle usw.) bleiben unsichtbar. | |||
Ohne <code>data-filter</code> zeigt die Karte '''alle''' Orte, unabhängig von | |||
der Kategorie. | |||
=== Mehrere Kategorien gleichzeitig zeigen === | |||
Im Filter können mehrere Kategorien kommagetrennt angegeben werden. Die Karte | |||
zeigt dann alle Orte, deren Kategorie '''eine der genannten''' ist – praktisch | |||
z.B. für „alle Essensmöglichkeiten in Gehweite": | |||
<pre> | |||
<div class="wikimap" data-filter="asiatisch,gasthaus,imbiss"></div> | |||
</pre> | |||
Leerzeichen nach den Kommas sind erlaubt. Zur Erinnerung: ganz ohne | |||
<code>data-filter</code> werden weiterhin '''alle''' Orte gezeigt. | |||
=== Wichtig: exakte Schreibweise === | |||
Die Kategorie im Filter muss '''zeichengenau''' mit der Kategorie in der | |||
Orte-Datei übereinstimmen – Groß-/Kleinschreibung zählt: | |||
{| class="wikitable" | |||
! In der JSON !! Im Filter !! Funktioniert? | |||
|- | |||
| <code>hausarzt</code> || <code>data-filter="hausarzt"</code> || ja | |||
|- | |||
| <code>hausarzt</code> || <code>data-filter="Hausarzt"</code> || nein | |||
|} | |||
'''Empfehlung:''' Kategorien durchgehend kleinschreiben, ohne Leerzeichen. So | |||
bleibt es einheitlich und fehlerfrei. | |||
=== Kategorien eine Farbe zuweisen === | |||
Jede Kategorie kann eine eigene Pin-Farbe bekommen. Die Zuordnung steht | |||
'''einmal zentral''' am Anfang von <code>MediaWiki:WikiMap-Orte.json</code> | |||
im Block <code>kategorien</code>: | |||
<pre> | |||
{ | |||
"kategorien": { | |||
"hausarzt": "#c0392b", | |||
"kardiologe": "#e74c3c", | |||
"bahnhof": "#708090", | |||
"asia": "#2ecc71" | |||
}, | |||
"orte": [ | |||
... | |||
] | |||
} | |||
</pre> | |||
Jeder Pin bekommt automatisch die Farbe seiner Kategorie – überall im Wiki | |||
gleich. Eine Farbe ändern heißt: eine Zeile ändern. | |||
Die Farben sind [https://de.wikipedia.org/wiki/Hexadezimale_Farbdefinition | |||
Hex-Farbcodes] (z.B. <code>#c0392b</code> für ein dunkles Rot). Farbwähler | |||
gibt es online, z.B. bei der Suche nach „color picker". | |||
'''Regeln und Sonderfälle:''' | |||
* Kategorien '''ohne''' Farbeintrag bleiben in der blauen Standardfarbe. | |||
* Der '''aktive''' Pin (<code>data-aktiv-ort</code>) bleibt immer rot und | |||
pulsierend – seine Hervorhebung hat Vorrang vor der Kategoriefarbe. | |||
* Ganz ohne <code>kategorien</code>-Block sind alle Pins blau wie bisher. | |||
'''Empfehlung Farbfamilien:''' Verwandte Kategorien in verwandten Farbtönen | |||
halten – z.B. alle Ärzte in Rottönen (jedes Fachgebiet ein anderer), Essen in | |||
Orange-/Grüntönen, Verkehr in Grau. So erkennt man die Grobrichtung auf einen | |||
Blick und das Detail beim genauen Hinsehen. | |||
=== Kombination mit anderen Attributen === | |||
<code>data-filter</code> lässt sich mit den übrigen Attributen kombinieren. | |||
Beispiel – nur Hausärzte zeigen und einen bestimmten hervorheben: | |||
<pre> | |||
<div class="wikimap" data-filter="hausarzt" data-aktiv-ort="Dr. Mustermann"></div> | |||
</pre> | |||
Aktuelle Version vom 3. Juli 2026, 00:27 Uhr
Technische Dokumentation: Kartenprojekt (WikiMap)
Das Kartenprojekt bindet interaktive Leaflet-Karten in Wiki-Seiten ein. Diese Dokumentation erklärt alle beteiligten Dateien, ihren Speicherort und ihre Funktion.
Die zwei Speicherorte
Das Projekt lebt an zwei getrennten Orten. Diese nicht zu verwechseln ist wichtig:
- Server (FTP) unter
/resources/lib/leaflet/– hier liegen
die fertigen Programmbibliotheken, die nicht bearbeitet werden.
- Wiki-Seiten im
MediaWiki:-Namespace – hier liegt der
eigene Code und die Daten, versioniert und bearbeitbar.
Server-Dateien (FTP)
Einmal hochgeladen, danach unverändert. Es sind die unveränderten Leaflet-Bibliotheksdateien:
| Datei | Funktion |
|---|---|
leaflet.js |
Die eigentliche Kartenbibliothek – zeichnet
Karten, reagiert auf Zoom und Klick, setzt Pins. |
leaflet.css |
Das Aussehen von Leaflet. |
Control.FullScreen.umd.js |
Das Vollbild-Plugin. |
Control.FullScreen.css |
Aussehen des Vollbild-Plugins. |
images/ |
Grafiken, die Leaflet benötigt (Marker-Schatten etc.). |
Diese Dateien sind „fremder" Code, der nur lokal gehostet wird, damit der Browser sie laden kann, ohne von externen Servern abhängig zu sein (DSGVO, keine CDN-Abhängigkeit).
Wiki-Seiten
Das eigentliche Projekt. Jede Seite hat eine klare Aufgabe:
| Seite | Funktion |
|---|---|
MediaWiki:Gadget-WikiMap.js |
Herzstück. Lädt Leaflet von
den Server-Dateien, definiert die fünf Kartenansichten, liest die Ortsdaten, zeichnet die Pins und hebt den aktiven hervor. Änderungen am Kartenverhalten passieren fast immer hier. |
MediaWiki:Gadget-WikiMap.css |
Bestimmt das Aussehen der Karten
– Größe des Kartenfensters und Optik der Pins (inkl. des pulsierenden roten aktiven Pins). |
MediaWiki:WikiMap-Orte.json |
Zentrale Datenquelle für alle
Stecknadeln. Jeder Ort steht hier genau einmal. Enthält außerdem die Farbzuordnung der Kategorien. Kernidee: eine Stelle für alle Pins, überall im Wiki automatisch aktuell. |
MediaWiki:WikiMap-Gemeinden.json |
Datenquelle für die
Gemeinde-Umrisse. Enthält die GeoJSON-Polygone aller Gemeinden; beim Klick auf einen Umriss springt man zur jeweiligen Gemeinde-Seite. |
MediaWiki:Gadgets-definition |
Registrierung. Eine Zeile
sagt MediaWiki, dass das Gadget existiert und aus welchen Seiten es besteht. Ohne diese Zeile passiert nichts. |
Einbindung auf einer Seite
Auf einer normalen Wiki-Seite genügt ein leeres Element:
<div class="wikimap" data-aktiv-ort="Ternitz Bahnhof"></div>
Das class="wikimap" ist das Signal „hier soll eine Karte hin".
Das data-aktiv-ort nennt die ID des hervorgehobenen Ortes. Die
Karte holt sich Position und alle anderen Pins selbst aus der zentralen JSON.
Alle verfügbaren Attribute:
| Attribut | Wirkung |
|---|---|
data-aktiv-ort |
ID des hervorgehobenen Ortes (rot,
pulsierend, zentriert, Popup offen) |
data-filter |
Nur Orte bestimmter Kategorien zeigen; mehrere
kommagetrennt möglich |
data-gemeinden="ja" |
Gemeinde-Umrisse einblenden |
data-hoehe |
Kartenhöhe in Pixeln (sonst CSS-Standard) |
Orte anlegen: die Felder
Jeder Ort in MediaWiki:WikiMap-Orte.json besteht aus wenigen
Feldern. Die id ist zugleich Anzeigename und Ziel-Wikiseite –
die Regel lautet: Ort heißt wie seine Wiki-Seite.
| Feld | Pflicht? | Bedeutung |
|---|---|---|
id |
ja | Eindeutiger Name. Erscheint im Popup und ist
zugleich die Ziel-Wikiseite beim Klick. |
geo |
ja* | Koordinaten als Text "lat,lon" –
direkt aus OSM.org oder OrganicMaps kopierbar. Beispiel:
|
lat / lon |
ja* | Alternative zu
|
kategorie |
nein | Für Filter und Pin-Farben. |
seite |
nein | Übersteuert das Klick-Ziel: ein anderer
Wiki-Seitenname oder eine externe Adresse (beginnend mit
|
* Entweder geo oder lat+lon
muss vorhanden sein. Sind beide da, gewinnt geo.
Ein Ort im Normalfall – drei Felder genügen:
{
"id": "Ternitz Bahnhof",
"geo": "47.7073509,15.9933643",
"kategorie": "bahnhof"
}
Ein Ort mit externer Website statt Wiki-Seite:
{
"id": "Dr. Mustermann",
"geo": "47.7,16.0",
"kategorie": "hausarzt",
"seite": "https://praxis-mustermann.at"
}
Fehlerverhalten: Ist das geo-Feld fehlerhaft (z.B.
Tippfehler, Buchstaben statt Zahlen), wird der Ort nicht angezeigt. Der
fehlende Pin fällt auf – dann in der JSON nachsehen.
Ablauf beim Seitenaufruf
- Jemand öffnet eine Wiki-Seite mit Karte.
- MediaWiki liefert die Seite plus das Gadget (weil in der Gadgets-Definition
registriert).
- Das Gadget erkennt das
.wikimap-Element und lädt Leaflet von den
Server-Dateien nach.
- Es holt die Ortsdaten aus
WikiMap-Orte.json. - Es zeichnet die Karte mit allen Pins und zoomt auf den aktiven Ort.
Zusammenhang (Hierarchie)
- Fundament: die Server-Dateien (Leaflet selbst).
- Darauf sitzt der Gadget-Code (
.js+.css),
der das Verhalten bestimmt.
- Der Code zieht seine Daten aus den zwei JSON-Seiten (Orte + Gemeinden).
- Einzelne Wiki-Seiten lösen mit einem einzeiligen
<div>
die Karte aus.
- Die Gadgets-Definition ist der Schalter, der das Ganze aktiviert.
Gemeinde-Umrisse
Zusätzlich zu den Stecknadeln kann die Karte die Umrisse von Gemeinden anzeigen. Klickt man auf einen Umriss, springt man zur jeweiligen Gemeinde-Wikiseite. Diese Funktion ist offen angelegt – es können laufend neue Gemeinden ergänzt werden.
Wie es technisch funktioniert
Eine Gemeindegrenze ist eine Kette aus tausenden Koordinaten-Punkten, die
zusammen den Umriss ergeben. Diese Umrisse liegen gebündelt in der Wiki-Seite
MediaWiki:WikiMap-Gemeinden.json im sogenannten
GeoJSON-Format.
Jede Gemeinde ist dort ein „Feature" mit zwei Teilen:
- Geometrie – die Koordinatenkette des Umrisses
- Eigenschaften –
name(Anzeigename) undseite
(Ziel-Wikiseite beim Klick)
Damit eine Karte die Umrisse zeigt, muss das Element auf der Seite das Attribut
data-gemeinden="ja" tragen:
<div class="wikimap" data-gemeinden="ja"></div>
Eine neue Gemeinde hinzufügen
Der Vorgang besteht aus zwei Schritten: erst die Umrisse von OpenStreetMap holen, dann mit dem Skript zur fertigen Datei zusammenbauen.
Schritt 1: Umriss von OpenStreetMap holen
- Die Gemeinde auf OpenStreetMap suchen und die
Relation-ID der Gemeindegrenze herausfinden (z.B. über die Suche oder die Detailansicht der Grenze).
- Den Umriss als GeoJSON beziehen. Zwei bewährte Wege:
- polygons.openstreetmap.fr – Relation-ID
eingeben, GeoJSON herunterladen. Einfachster Weg.
- Alternativ:
https://www.openstreetmap.org/api/0.6/relation/ID/full
- Alternativ:
aufrufen (das /full am Ende lädt die Koordinaten mit!) und die
XML-Datei durch osmtogeojson in GeoJSON
umwandeln.
- Wichtig: Eine XML ohne
/fullenthält keine Koordinaten und
ist unbrauchbar.
Schritt 2: Datei richtig benennen
Die GeoJSON-Datei MUSS exakt so heißen wie die Gemeinde und die
zugehörige Wiki-Seite. Erster Buchstabe groß, Endung .geojson:
- Gemeinde „Ternitz", Wiki-Seite „Ternitz" → Datei
Ternitz.geojson - Gemeinde „Altendorf", Wiki-Seite „Altendorf" → Datei
Altendorf.geojson
Der Dateiname bestimmt automatisch den Anzeigenamen und das Klick-Ziel. Stimmt er nicht mit der Wiki-Seite überein, führt der Klick ins Leere.
Schritt 3: Zusammenbauen mit dem Skript
- Alle Gemeinde-Dateien in einen Ordner namens
gemeindenlegen. - Das Skript
gemeinden-bauen.py(siehe unten) daneben legen. - Ausführen:
python3 gemeinden-bauen.py(unter Windows:
py gemeinden-bauen.py)
- Es entsteht die Datei
WikiMap-Gemeinden.json. - Deren kompletten Inhalt in die Wiki-Seite
MediaWiki:WikiMap-Gemeinden.json kopieren und speichern.
Das Skript verarbeitet immer alle Dateien im Ordner. Zum Ergänzen also einfach die neue Datei dazulegen und das Skript erneut laufen lassen – die bestehenden Gemeinden bleiben erhalten.
Das Skript: gemeinden-bauen.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
gemeinden-bauen.py
==============================================================================
Baut aus einzelnen Gemeinde-GeoJSON-Dateien EINE WikiMap-Gemeinden.json,
die das WikiMap-Gadget einlesen kann.
WIE BENUTZEN
------------
1. Lege fuer jede Gemeinde eine GeoJSON-Datei in den Ordner "gemeinden".
Der Dateiname MUSS dem Gemeinde- und Wiki-Seitennamen entsprechen:
Ternitz.geojson -> Gemeinde "Ternitz", Wiki-Seite "Ternitz"
Altendorf.geojson -> Gemeinde "Altendorf", Wiki-Seite "Altendorf"
(Endung .geojson oder .json. Umlaute im Namen sind erlaubt.)
2. Skript ausfuehren:
python3 gemeinden-bauen.py
3. Es entsteht die Datei "WikiMap-Gemeinden.json". Deren kompletten Inhalt
in die Wiki-Seite MediaWiki:WikiMap-Gemeinden.json kopieren.
WAS DAS SKRIPT MACHT
--------------------
Jede Einzeldatei enthaelt nur nackte Geometrie (type + coordinates).
Das Gadget braucht aber pro Gemeinde zusaetzlich "name" und "seite".
Das Skript verpackt deshalb jede Geometrie in ein GeoJSON-"Feature" mit
diesen Eigenschaften und fuegt alle zu einer FeatureCollection zusammen.
Der Gemeindename wird aus dem Dateinamen abgeleitet (ohne Endung).
name und seite werden gleich gesetzt (Wiki-Seite = Gemeindename).
==============================================================================
"""
import json
import os
import sys
# Ordner, in dem die einzelnen Gemeinde-Dateien liegen.
QUELL_ORDNER = "gemeinden"
# Name der Ausgabedatei.
ZIEL_DATEI = "WikiMap-Gemeinden.json"
def lade_geometrie(pfad):
"""Liest eine GeoJSON-Datei und gibt deren Geometrie zurueck.
Akzeptiert zwei Formen:
a) Nackte Geometrie: {"type": "MultiPolygon", "coordinates": [...]}
b) Bereits ein Feature: {"type": "Feature", "geometry": {...}, ...}
In beiden Faellen wird das Geometrie-Objekt zurueckgegeben.
"""
with open(pfad, "r", encoding="utf-8") as f:
daten = json.load(f)
typ = daten.get("type")
if typ in ("Polygon", "MultiPolygon", "GeometryCollection"):
# Form a) nackte Geometrie
return daten
if typ == "Feature":
# Form b) bereits ein Feature -> nur die Geometrie nehmen
return daten.get("geometry")
if typ == "FeatureCollection":
# Ungewoehnlich: eine Sammlung in einer Einzeldatei.
# Wir nehmen die erste Geometrie.
feats = daten.get("features", [])
if feats:
return feats[0].get("geometry")
raise ValueError("FeatureCollection ohne features")
raise ValueError("Unbekannter GeoJSON-Typ: %r" % typ)
def main():
if not os.path.isdir(QUELL_ORDNER):
print("FEHLER: Ordner '%s' existiert nicht." % QUELL_ORDNER)
print("Lege ihn an und lege die Gemeinde-GeoJSON-Dateien hinein.")
sys.exit(1)
features = []
dateien = sorted(os.listdir(QUELL_ORDNER))
verarbeitet = 0
for dateiname in dateien:
if not (dateiname.endswith(".geojson") or dateiname.endswith(".json")):
continue
# Gemeindename = Dateiname ohne Endung.
name = os.path.splitext(dateiname)[0]
pfad = os.path.join(QUELL_ORDNER, dateiname)
try:
geometrie = lade_geometrie(pfad)
except Exception as e:
print(" UEBERSPRUNGEN: %s (%s)" % (dateiname, e))
continue
if not geometrie:
print(" UEBERSPRUNGEN: %s (keine Geometrie gefunden)" % dateiname)
continue
features.append({
"type": "Feature",
"properties": {
"name": name,
"seite": name
},
"geometry": geometrie
})
verarbeitet += 1
print(" + %s" % name)
if not features:
print("FEHLER: Keine gueltigen GeoJSON-Dateien gefunden.")
sys.exit(1)
sammlung = {
"type": "FeatureCollection",
"features": features
}
with open(ZIEL_DATEI, "w", encoding="utf-8") as f:
json.dump(sammlung, f, ensure_ascii=False, separators=(",", ":"))
print("")
print("Fertig: %d Gemeinde(n) in '%s' geschrieben." % (verarbeitet, ZIEL_DATEI))
print("Inhalt dieser Datei in MediaWiki:WikiMap-Gemeinden.json kopieren.")
if __name__ == "__main__":
main()
Format der fertigen Datei
Zur Veranschaulichung – so sieht eine fertige WikiMap-Gemeinden.json
mit zwei Gemeinden im Aufbau aus (Koordinaten gekürzt):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "name": "Altendorf", "seite": "Altendorf" },
"geometry": { "type": "MultiPolygon", "coordinates": [ ... ] }
},
{
"type": "Feature",
"properties": { "name": "Ternitz", "seite": "Ternitz" },
"geometry": { "type": "MultiPolygon", "coordinates": [ ... ] }
}
]
}
Tipp: große Dateien
Detaillierte Umrisse können sehr groß werden. Wird die Karte dadurch träge, lassen sich die Polygone vorab vereinfachen – z.B. mit der „Simplify"-Funktion auf mapshaper.org oder direkt beim Export auf polygons.openstreetmap.fr. Eine leichte Vereinfachung verkleinert die Datei deutlich, ohne dass die Umrisse sichtbar eckig werden.
Kategorien, Filter und Farben
Jeder Ort kann eine kategorie haben. Kategorien haben zwei
Funktionen: Sie steuern, welche Orte auf einer Karte erscheinen
(Filter), und welche Farbe die Pins haben (Farbzuordnung).
Kategorie einem Ort zuweisen
In der Orte-Datei bekommt ein Eintrag eine kategorie. Beispiel:
{
"id": "Dr. Mustermann",
"geo": "47.7,16.0",
"kategorie": "hausarzt"
}
Alle Orte mit derselben Kategorie gehören zur selben Gruppe. Man kann beliebige
Kategorien erfinden – etwa hausarzt, bahnhof,
wasserfall, gasthaus.
Nur eine Kategorie auf einer Karte zeigen
Auf einer Themenseite (z.B. „Hausärzte") bindet man die Karte mit dem Attribut
data-filter ein:
<div class="wikimap" data-filter="hausarzt"></div>
Die Karte zeigt dann nur die Pins mit der Kategorie hausarzt.
Alle anderen Orte (Bahnhöfe, Wasserfälle usw.) bleiben unsichtbar.
Ohne data-filter zeigt die Karte alle Orte, unabhängig von
der Kategorie.
Mehrere Kategorien gleichzeitig zeigen
Im Filter können mehrere Kategorien kommagetrennt angegeben werden. Die Karte zeigt dann alle Orte, deren Kategorie eine der genannten ist – praktisch z.B. für „alle Essensmöglichkeiten in Gehweite":
<div class="wikimap" data-filter="asiatisch,gasthaus,imbiss"></div>
Leerzeichen nach den Kommas sind erlaubt. Zur Erinnerung: ganz ohne
data-filter werden weiterhin alle Orte gezeigt.
Wichtig: exakte Schreibweise
Die Kategorie im Filter muss zeichengenau mit der Kategorie in der Orte-Datei übereinstimmen – Groß-/Kleinschreibung zählt:
| In der JSON | Im Filter | Funktioniert? |
|---|---|---|
hausarzt |
data-filter="hausarzt" |
ja |
hausarzt |
data-filter="Hausarzt" |
nein |
Empfehlung: Kategorien durchgehend kleinschreiben, ohne Leerzeichen. So bleibt es einheitlich und fehlerfrei.
Kategorien eine Farbe zuweisen
Jede Kategorie kann eine eigene Pin-Farbe bekommen. Die Zuordnung steht
einmal zentral am Anfang von MediaWiki:WikiMap-Orte.json
im Block kategorien:
{
"kategorien": {
"hausarzt": "#c0392b",
"kardiologe": "#e74c3c",
"bahnhof": "#708090",
"asia": "#2ecc71"
},
"orte": [
...
]
}
Jeder Pin bekommt automatisch die Farbe seiner Kategorie – überall im Wiki gleich. Eine Farbe ändern heißt: eine Zeile ändern.
Die Farben sind [https://de.wikipedia.org/wiki/Hexadezimale_Farbdefinition
Hex-Farbcodes] (z.B. #c0392b für ein dunkles Rot). Farbwähler
gibt es online, z.B. bei der Suche nach „color picker".
Regeln und Sonderfälle:
- Kategorien ohne Farbeintrag bleiben in der blauen Standardfarbe.
- Der aktive Pin (
data-aktiv-ort) bleibt immer rot und
pulsierend – seine Hervorhebung hat Vorrang vor der Kategoriefarbe.
- Ganz ohne
kategorien-Block sind alle Pins blau wie bisher.
Empfehlung Farbfamilien: Verwandte Kategorien in verwandten Farbtönen halten – z.B. alle Ärzte in Rottönen (jedes Fachgebiet ein anderer), Essen in Orange-/Grüntönen, Verkehr in Grau. So erkennt man die Grobrichtung auf einen Blick und das Detail beim genauen Hinsehen.
Kombination mit anderen Attributen
data-filter lässt sich mit den übrigen Attributen kombinieren.
Beispiel – nur Hausärzte zeigen und einen bestimmten hervorheben:
<div class="wikimap" data-filter="hausarzt" data-aktiv-ort="Dr. Mustermann"></div>