In dieser Übung geht es darum die Bahnlinie des Glacier Express von Zermatt nach St. Moritz, durch die Alpen zu visualisieren.
-
Erstelle eine Karte in einem passenden Format (z.B. 4:3 — 800x600), die auf die Schweiz fokussiert ist (siehe Hinweis 1).
-
Erstelle eine GeoJSON Linie anhand der Koordinaten in
routeStops(siehe Hinweis 2). -
Binde diese Linie an einen Pfad mithilfe eines Pfadgenerators (siehe Hinweis 3).
-
Binde die Haltestellen in
routeStopsan Kreise und rendere diese auf deiner Karte. Zeige dabei nur die Haltestellen, welche tatsächlich from Glacier Express benutzt werden (sie sind mit einemisMajorAttribut markiert).
Für diese Karte kannst du die Projektion aus der Abstimmungsübung nehmen:
const projection = d3.geoAlbers()
.center([0, 46.7])
.rotate([-9, 0, 0])
.parallels([40, 50])
.scale(12500)Korrekterweise könnte man hier auch die Lambert Conic Conformal Kartenprojektion verwenden. Diese Kartenprojektion wird von Piloten verwendet um Distanzen korrekt abzumessen. Da in diesem Fall die Distanz nicht besonders wichtig ist, und diese Karte nicht von Piloten oder Navigatoren benutzt werden sollte, haben wir freiere Wahl.
In diesem Fall gibt es keine Kantone mehr, da uns nur die Landesgrenze interessiert. Du must die Kantone also nicht mit .selectAll an Daten binden. Du kannst einfach .append benutzen.
const pathGenerator = d3.geoPath().projection(projection)
const countryShape = svg.append("path")
.attr("d", pathGenerator(country))
.attr("fill", "#EEE")Um eine GeoJSON Linie zu erstellen brauchst du eine Liste von Koordinaten. Du brauchst nur jeweils einen Array von Koordinaten (z.B. [7.747727, 46.024393]) von jeder Haltestelle.
Um einen Array in einen anderen Array umzuwandeln kannst du Array.map benutzen.
const routeStops = [
{ "coordinates": [7.747727, 46.024393], "name":"Zermatt" },
{ "coordinates": [7.774707, 46.067162], "name":"Täsch" },
{...}
]
const routeStopsCoordinates = routeStops.map(function(routeStop) {
return routeStop.coordinates
})
console.log(routeStopsCoordinates) // [ [7.747727, 46.024393], [7.774707, 46.067162] ]Mithilfe von Array.map kannst du jetz relativ einfach eine Koordinatenliste zusammenstellen und sie in deiner GeoJSON Linie an das coordinates Attribut hängen:
const routeStops = [
{ "coordinates": [7.747727, 46.024393], "name":"Zermatt" },
{ "coordinates": [7.774707, 46.067162], "name":"Täsch" },
{...}
]
const lineData = {
type: "Feature",
geometry: {
type: "LineString",
coordinates: routeStops.map(function(routeStop) { return routeStop.coordinates }),
},
}Um eine Linie mit einem d3 Pfadgenerator zu rendern brauchst du eine GeoJSON linie (siehe Hinweis 2). In diesem Fall handelt es sich nur um eine Linie also musst du nicht selectAll, oder enter benutzen.
const lineData = {
type: "Feature",
geometry: {...},
}
const line = svg.append("path")
.attr("d", pathGenerator(lineData))Wenn dir diese Aufgabe zu einfach ist, kanns du bereits versuchen die Linie zu animieren. Um eine Linie zu animieren musst du zuerst wissen wie lang die Linie ist. Dann kannst du mit stroke-dasharray und stroke-dashoffset die zeichnung der Linie simulieren.
const pathLength = pathGenerator.measure(lineData)Mithilfe von stroke-dasharray, stroke-dashoffset, und pathLength kannst du die Linie 'unsichtbar' machen.
line
.attr("stroke-dasharray", pathLength)
.attr("stroke-dashoffset", pathLength)Benutze d3.transition um deine Linie zu animieren.
line
.transition()
.duration(5000)
.delay(500)
.attr("stroke-dashoffset", 0)