WikiMap: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) |
Admin (Diskussion | Beiträge) |
||
| Zeile 346: | Zeile 346: | ||
deutlich, ohne dass die Umrisse sichtbar eckig werden. | deutlich, ohne dass die Umrisse sichtbar eckig werden. | ||
<br><br><br><br> | |||
== Kategorien und Filter == | == Kategorien und Filter == | ||
Version vom 1. Juli 2026, 18: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, mit Name, Koordinaten, Ziel-Wikiseite und Kategorie. 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="gaestehaus-mustertal"></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.
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 - 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
<syntaxhighlight lang="python">
- !/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()
</syntaxhighlight>
Format der fertigen Datei
Zur Veranschaulichung – so sieht eine fertige WikiMap-Gemeinden.json
mit zwei Gemeinden im Aufbau aus (Koordinaten gekürzt):
<syntaxhighlight lang="json"> {
"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": [ ... ] }
}
]
} </syntaxhighlight>
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 und Filter
Jeder Ort in MediaWiki:WikiMap-Orte.json hat ein Feld
kategorie. Damit lassen sich Karten bauen, die nur bestimmte
Arten von Orten zeigen – zum Beispiel eine Karte, die ausschließlich
Hausärzte anzeigt.
Kategorie einem Ort zuweisen
In der Orte-Datei bekommt jeder Eintrag eine kategorie. Beispiel:
{
"id": "dr-mustermann",
"name": "Dr. Mustermann",
"seite": "Dr. Mustermann",
"lat": 47.7,
"lon": 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.
Wichtig: exakte Schreibweise
Die Kategorie im Filter muss zeichengenau mit der Kategorie in der Orte-Datei übereinstimmen:
| In der JSON | Im Filter | Funktioniert? |
|---|---|---|
hausarzt |
data-filter="hausarzt" |
ja |
hausarzt |
data-filter="Hausarzt" |
nein (Großbuchstabe) |
hausarzt |
data-filter="hausärzte" |
nein (Mehrzahl, Umlaut) |
Empfehlung: Kategorien durchgehend kleinschreiben, in der Einzahl, ohne Umlaute und ohne Leerzeichen. So bleibt es einheitlich und fehlerfrei.
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>