Als Vorlage für das HTML Grundgerüst verwenden wir template.zip -> auspacken als username.github.io/wien
.
Dieses Template enthält als Hintergrundlayer für die Grundkarte die frei verfügbaren WMTS-Layer von basemap.at, die über das leaflet-providers Plugin eingebunden werden. Die Kombination von Orthofoto mit Beschriftung wird über L.layerGroup implementiert
let startLayer = L.tileLayer.provider("BasemapAT.grau");
L.control.layers({
"BasemapAT.grau": startLayer,
"BasemapAT": L.tileLayer.provider("BasemapAT"),
"BasemapAT.highdpi": L.tileLayer.provider("BasemapAT.highdpi"),
"BasemapAT.terrain": L.tileLayer.provider("BasemapAT.terrain"),
"BasemapAT.surface": L.tileLayer.provider("BasemapAT.surface"),
"BasemapAT.orthofoto": L.tileLayer.provider("BasemapAT.orthofoto"),
"BasemapAT.overlay": L.tileLayer.provider("BasemapAT.overlay"),
"BasemapAT.orthofoto+overlay": L.layerGroup([
L.tileLayer.provider("BasemapAT.orthofoto"),
L.tileLayer.provider("BasemapAT.overlay")
])
}.addTo(map);
https://data.gv.at -> Suche nach “Stadtspaziergang”
Stadtspaziergang Wien ansteuern und dort zu WFS GetFeature (JSON) wechseln
Der Link “Zur Ressource” lässt uns die GeoJSON Daten im Visual Studio Code öffnen.
wir schreiben eine Variablendeklaration const SPAZIERGANG =
vor die geschwungene Klammer des GeoJSON-Objekts und speichern das, dadurch gültige Javascript als SPAZIERPUNKTOGD.js
STRG+UMSCHALT+P und Beautify file in Visual Studio Code zeigt die Struktur von GeoJSON noch besser - das auf einen Eintrag reduzierte GeoJSON File sieht dann so aus:
const SPAZIERGANG = {
"type": "FeatureCollection",
"totalFeatures": 126,
"features": [{
"type": "Feature",
"id": "SPAZIERPUNKTOGD.8609",
"geometry": {
"type": "Point",
"coordinates": [16.357561781399717, 48.21086163580665]
},
"geometry_name": "SHAPE",
"properties": {
"OBJECTID": 8609,
"KATEGORIE": 5,
"NAME": "Rathaus",
"BEMERKUNG": "Das von 1872 bis 1883 von Friedrich von Schmidt erbaute Wiener Rathaus ist der bedeutendste nichtkirchliche Bau Wiens im neugotischen Stil.",
"ADRESSE": "1., Rathausplatz 1",
"WEITERE_INF": "http://www.wien.gv.at/spaziergang/ringlinien/rathaus.html",
"SE_ANNO_CAD_DATA": null
}
}],
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:EPSG::4326"
}
}
};
Im features
-Array sind die einzelnen Stopps des Spaziergangs mit Koordinaten und Attributen, die wir in Javascript folgendermaßen ansprechen können:
das erste Feature des Datensatzes:
let point = SPAZIERGANG.features[0]
die Koordinaten dieses Punkts
point.geometry.coordinates[0] // lng
point.geometry.coordinates[1] // lat
Attribute dieses Punkts
point.properties.NAME // der Name des Stopps
point.properties.BEMERKUNG // die Info zum Stopps
point.properties.ADRESSE // die Adresse des Stopps
point.properties.WEITERE_INF // der Link zur Webseite des Stopps
Details zur GeoJSON-Spezifikation finden sich auf https://geojson.org/
zuerst binden wir das Skript mit unserem GeoJSON-Objekt in index.html ein
<script src="SPAZIERPUNKTOGD.js"></script>
Zur Anzeige der GeoJSON-Daten als einfache Marker verwenden wir Leaflets L.geoJson Methode der wir als ersten Parameter unser GeoJSON-Objekt in der Variablen SPAZIERGANG
übergeben
let sights = L.geoJson(SPAZIERGANG).addTo(map);
damit werden automatisch alle Punkte als Marker angezeigt
das Popup können wir im Options-Objekt von L.geoJson über die Funktion pointToLayer implementieren. Als Argumente werden an pointToLayer automatisch das GeoJSON Feature selbst mit seinen geometry
und properties
Objekten sowie zusätzlich die Position in Lat/Lng übergeben. Sobald wir pointToLayer verwenden, erwartet L.geoJson, dass wir einen Marker mit return
zurückliefern. Tun wir das nicht, wird unser Marker auch nicht mehr angezeigt. Das Popup definieren wir aus den properties
mit Template-Syntax.
let sights = L.geoJson(SPAZIERGANG, {
pointToLayer: function (point, latlng) {
let marker = L.marker(latlng);
marker.bindPopup(`
<h3>${point.properties.NAME}</h3>
<p>${point.properties.BEMERKUNG || ""}</p>
<p>Adresse: ${point.properties.ADRESSE}</p>
<p><a target="links" href="${point.properties.WEITERE_INF}">Weiterführende Informationen</a></p>
`);
return marker;
}
}).addTo(map);
das logische oder Zeichen ||
in point.properties.BEMERKUNG || ""
bewirkt, dass das Attribut BEMERKUNG
nur angezeigt wird, wenn es auch mit einem Wert belegt ist. Ist es leer wird eine leere Zeichenkette angezeigt
target="links"
beim Link zu den weiterführenden Informationen bewirkt, dass alle externen Seiten im gleichen Browser-Tab, dem wir damit den Name link
gegeben haben, geöffnet werden.
Möchten wir statt der Standardmarker ein eigenes Icon verwenden, können wir das beim Marker über L.icon implementieren
das Icon im Format SVG bekommen wir auf der Icons-Seite der Stadt Wien unter Sehenswürdigkeiten – Standorte (svg) - wir speichern es in einem Unterverzeichnis icons/
mit dem Namen sight.svg
Icon-Link und Größe definieren wir mit L.icon
in den Attributen iconUrl und iconSize
let siteIcon = L.icon({
iconUrl: "icons/sight.svg",
iconSize: [32, 32]
});
beim Marker verwenden wir unser neues Icon über das gleichnamige Attribut icon
let marker = L.marker(latlng, {
icon: siteIcon
});
Den Zwischenschritt der Umwandlung der GeoJSON-Daten in gültiges Javascript über die const SPAZIERGANG
Deklaration mit Abspeichern als .js
-File können wir weglassen, wenn wir die Daten direkt vom Server der Stadt Wien laden
das Leaflet Plugin unserer Wahl dazu ist leaflet.ajax von calvinmetcalf
wir binden es über cdnjs.com in index.html ein
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js"></script>
definieren die URL des GeoJSON-Files als Variable sightUrl
let sightUrl = "https://data.wien.gv.at/daten/geo?service=WFS&request=GetFeature&version=1.1.0&typeName=ogdwien:SPAZIERPUNKTOGD&srsName=EPSG:4326&outputFormat=json";
und ersetzen L.geoJson
mit L.geoJson.ajax
. Statt der Konstanten SPAZIERGANG
verwenden wir die sightUrl
als ersten Parameter, der Rest bleibt gleich
```javascript let sights = L.geoJson.ajax(sightUrl, { // … }).addTo(map)
```
Möchten wir die Icons in ein eigenes Overlay schreiben das wir in der Layernavigation ein- und ausschalten können, müssen wir folgende Schritt umsetzen
wir definieren direkt oberhalb von L.control.layers eine neue L.featureGroup und hängen sie an die Karte
let sightGroup = L.featureGroup().addTo(map);
in L.control.layers können wir neben den Hintergrundlayern auch Overlays als zweites Objekt einbauen. Der Key des Objekts wird der Label des Eintrags und der Value ist die Feature Group die wir ein- und ausschalten möchten
L.control.layers({
// baselayers
},{
"Stadtspaziergang (Punkte)": sightGroup
}).addTo(map);
bleibt noch, unsere Icons statt in die Karte map
in die Feature Group sightGroup
zu schreiben
let sights = L.geoJson.ajax(sightUrl, {
// ....
}).addTo(sightGroup)
Damit können die Icons in der Layer control rechts oben ein- und ausgeschaltet werden
wenn alle Icons gezeichnet sind, setzen wir in der data:loaded
Callback-Funktion des sights
-Objekts den Ausschnitt der Karte mit fitBounds auf die Ausdehnung unserer Icons die wir über getBounds abfragen können
sights.on("data:loaded", function() {
map.fitBounds(sightGroup.getBounds());
});
der JSON Datensatz dafür heißt Stadtwanderwege und RundumadumWanderweg Wien, die GeoJSON-Daten sind unter WFS GetFeature (JSON) - Wanderwege zu finden - die URL zum Laden lautet:
let walkUrl = "https://data.wien.gv.at/daten/geo?service=WFS&request=GetFeature&version=1.1.0&typeName=ogdwien:WANDERWEGEOGD&srsName=EPSG:4326&outputFormat=json";
die Visualisierung der Linie erfolgt analog zur Funktion pointToLayer bei Punkten über die Funktion style von L.geoJson. Dieser Funktion wird automatisch das jeweilige GeoJSON Feature übergeben. Es liefert ein Objekt zurück in dem das Aussehen der Linie definiert wird. Nachdem wir auch die properties
des GeoJSON Features zur Verfügung haben, können wir die Linien auch in Abhängigkeit von diesen Eigenschaften stylen.
TYP
strichliert (TYP 1
) oder punktiert (TYP 2
)if
-Abfrage entscheidet in Abhängigkeit des Typs, welcher Stil zurückgeliefert wird L.geoJson.ajax(walkUrl, {
style: function (feature) {
if (feature.properties.TYP == "1") {
return {
color: "black",
weight: 2,
dashArray: "15 5"
};
} else {
return {
color: "black",
weight: 2,
dashArray: "1 5"
};
}
}
}).addTo(map);
Alle Attribute zum Formatieren einer Linie liefert die Leaflet Hilfe unter Path
Tooltips für die Wanderwege implementieren wir in der onEachFeature Funktion von L.geoJson. Ihr wird automatisch das jeweilige GeoJSON Feature, sowie der dafür erzeugte Leaflet-Layer übergeben. An diesen Layer können wir unser Popup mit der Bezeichnung des Wanderwegs hängen
L.geoJson.ajax(walkUrl, {
style : function (feature) {
// ...
},
onEachFeature: function (feature, layer) {
layer.bindPopup(`<p>${feature.properties.BEZ_TEXT}</p>`);
}
}).addTo(map);
wie bei den Sehenswürdigkeiten zuvor, zeichnen wir die Wanderwege wieder in ein Overlay
vor L.control.layers
let walkGroup = L.featureGroup().addTo(map);
bei L.control.layers
L.control.layers({
// baselayers
},{
"Wanderungen": walkGroup
}
bei L.geoJson.ajax
L.geoJson.ajax(walkUrl, {
// ...
}).addTo(walkGroup)
der JSON Datensatz dafür heißt Weltkulturerbe Wien, die GeoJSON-Daten sind unter WFS GetFeature (JSON) - Wanderwege zu finden - die URL zum Laden lautet:
let heritageUrl = "https://data.wien.gv.at/daten/geo?service=WFS&request=GetFeature&version=1.1.0&typeName=ogdwien:WELTKULTERBEOGD&srsName=EPSG:4326&outputFormat=json";
die Visualisierung der Flächen erfolgt wie bei den Linien über die Funktion style von L.geoJson. Diesmal wollen wir zwischen Kernzonen (Rot transparent) und Pufferzonen (Gelb transparent) unterscheiden.
L.geoJson.ajax(heritageUrl, {
style: function (feature) {
if (feature.properties.TYP === "1") {
return {
color: "salmon",
fillOpacity: 0.3
};
} else {
return {
color: "yellow",
fillOpacity: 0.3
};
}
}
}).addTo(map);
Tooltips für die Zonen implementieren wir wieder in der onEachFeature Funktion von L.geoJson.
onEachFeature: function (feature, layer) {
layer.bindPopup(`
<h3>${feature.properties.NAME}</h3>
<p>${feature.properties.INFO}</p>
`);
}
wie bei den Sehenswürdigkeiten und Wanderwegen zuvor, zeichnen wir die Weltkulturerbe Flächen wieder in Overlay
vor L.control.layers
let heritageGroup = L.featureGroup().addTo(map);
bei L.control.layers
L.control.layers({
// baselayers
},{
"Weltkulturerbe": heritageGroup
}
bei L.geoJson.ajax
L.geoJson.ajax(heritageUrl, {
// ..
}).addTo(heritageGroup)
Die vielen Icons für Sehenswürdigkeiten machen die Karte schwer lesbar. Deshalb werden wir sie mit dem Leaflet.markercluster Plugin zu Clustern zusammenfassen.
zuerst binden wir das Plugin mit seinen Javascript und CSS files über cdnjs.com in index.html ein
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/leaflet.markercluster.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.Default.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.4.1/MarkerCluster.css">
dann definieren wir sightGroup
als L.markerClusterGroup
let sightGroup = L.markerClusterGroup().addTo(map);
Mit dem letzte Schritt verschwinden plötzlich alle Icons, denn Leaflet.markercluster kann seine Cluster erst dann zeichnen, wenn alle Icons erzeugt sind. Deshalb kommt das .addTo(sightGroup)
beim GeoJson-Aufruf zu früh und wir löschen es weg
sobald dann alle Marker gezeichnet sind, können wir die Markercluster Gruppe an die Karte hängen und den Ausschnitt setzen. Das Callback data:loaded
unseres GeoJSON Objekts sights
ermöglicht das - wir fügen dort mit addLayer unsere Icons dem Overlay hinzu
sights.on("data:loaded", function() {
sightGroup.addLayer(sights);
map.fitBounds(sightGroup.getBounds());
});