Wir erstellen zuerst die Funktion drawTemperature als Kopie von drawStations. Einzige Änderung (neben dem Namen der Funktion) ist die letzte Zeile, bei der wir die Marker an overlays.temperature hängen.
// Temperaturdaten
let drawTemperature = function(geojson) {
L.geoJSON(geojson, {
pointToLayer: function(geoJsonPoint, latlng) {
let popup = `
${geoJsonPoint.properties.name} (${geoJsonPoint.geometry.coordinates[2]}m)
`;
return L.marker(latlng, {
icon: L.icon({
iconUrl: "icons/wifi.png",
iconAnchor: [16, 37],
popupAnchor: [0, -37]
})
}).bindPopup(popup);
}
}).addTo(overlays.temperature);
}
Damit der Layer gezeigt wird, müssen wir drawTemperature(geojson) in unserer async function loadData(url) noch aufrufen
async function loadData(url) {
let response = await fetch(url);
let geojson = await response.json();
drawStations(geojson);
drawTemperature(geojson);
}
Damit wir beim Entwickeln nur unseren Temperatur Layer sehen, zeigen wir ihn statt dem Stationslayer beim Laden an. Den Kommentar der dort steht änderen wird gleich mit.
// diesen Layer beim Laden anzeigen
overlays.temperature.addTo(map);
Den Code der Option icon ersetzen wir mit einem L.divIcon(), dessen Optionen-Objekt aus zwei Key/Value Paaren besteht:
die Option className gibt jedem <div> Element das wir als Icon erstellen ein Klassenattribut class="aws-div-icon" - wir können es dann zum Stylen der Texte verwenden
die Option html bestimmt den HTML-Markup, der angezeigt werden soll. Wir setzen ihn als <span> Element mit Template Syntax und Backticks auf die Lufttemperatur im Attribut geoJsonPoint.properties.LT
icon: L.divIcon({
className: "aws-div-icon",
html: `<span>${geoJsonPoint.properties.LT}</span>`
})
Über die Klasse .aws-div-icon können wir die Texte des <span> Elements im Stylesheet main.css stylen:
aws-div-icon span {
font-size: 1.25em;
font-weight: bold;
padding: 0.3em;
border: 1px solid silver;
text-shadow:
-1px -1px 0 white,
-1px 1px 0 white,
1px -1px 0 white,
1px 1px 0 white
}
Die einzelnen CSS Regeln sind selbsterklärend, lediglich die text-shadow Anweisung ist für uns in dieser Form neu. Sie sorgt dafür, dass auf allen Seiten des Textes ein weißer Schatten entsteht, der den Text auch auf farbigem Hintergrund (wie wir ihn später implementieren werden) gut lesbar macht
Zwei Verbesserungen müssen wir in main.js noch implementieren. Vorallem die Stationen mit undefined bereiten uns Probleme, wir müssen sie daher beim Zeichnen ignorieren. Leaflet stellt uns dafür die GeoJSON Option filter zur Verfügung
Genau wie pointToLayer ist filter eine Funktion, die für jeden Marker ausgeführt wird. Liefert sie true zurück, wird der Marker gezeichnet. In der Funktion können wir auf die Attribute unseres Markers zugreifen und so entscheiden, ob wir true zurückgeben möchten. Wir schreiben die Option oberhalb von pointToLayer und liefern true zurück, wenn die Temperatur zwischen -50° und +50° liegt:
filter: function(geoJsonPoint) {
if (geoJsonPoint.properties.LT > -50 && geoJsonPoint.properties.LT < 50) {
return true;
}
}
Neu bei dieser if-Abfrage ist die Verknüpfung zweier Bedingungen mit dem Logical AND (&&) Operator
Damit verschwinden Stationen ohne Temperatur und wir können die zweite Verbesserung angehen - die Zahl der Nachkommastellen mit der Javascript Methode .toFixed auf eine Nachkommastelle festlegen:
html: `<span>${geoJsonPoint.properties.LT.toFixed(1)}</span>`
Dieser Schritt hätte ohne das Ausschließen von Stationen ohne Temperatur unser Skript gestoppt, denn der Versuch den Wert undefined auf eine Nachkommastelle zu formatieren wäre natürlich gescheitert.
Zur Umsetzung der Temperaturwerte in Farben der Rechtecke, definieren wir zunächst in einer neuen Javascript-Datei colors.js ein COLORS-Objekt mit Farbwerten und dazugehörigen min/max Schwellen. Visual Studio Code hilft uns beim Erstellen im <head> Bereich von index.html mit dem Baustein script:src und STRG-Klick auf den generierten Link. Den Kommentar dort erweiteren wir entsprechend.
<!-- eigene Stile, Farben und Hauptskript -->
<link rel="stylesheet" href="main.css">
<script src="colors.js"></script>
<script defer src="main.js"></script>
Die Farben mit Schwellen “leihen” wir uns von der Temperaturkarte von Lawinen.report. Mit Rechtsklick / Untersuchen bei den farbigen Legendenkästchen können wir die CSS Farbwerte der einzelnen Kästchen ablesen. Wir notieren sie als color mit min/max Schwellen in unserem COLORS-Objekt das a) eine Konstante ist, b) aus Objekten je nach Layern und c) darin aus einem Array von Objekten für die Definition besteht - so sieht es aus:
const COLORS = {
temperature: [{
min: -50,
max: -25,
color: "#9f80ff"
}, {
min: -25,
max: -20,
color: "#784cff"
}, {
// und so weiter
}
]
};
Das vorläufige Resultat ist in colors.js sichtbar. Später werden wir auch noch Farbpaletten für die anderen Layer hinzufügen …
Nachdem wir den Task eine Farbe für einen Wert nach Schwellen ermitteln noch öfters brauchen werden, definieren wir eine Funktion getColor, die das für uns übernehmen wird. Sie erwartet beim Aufruf den Wert und die Farbpalette mit Schwellen, die in der Funktion dann als value und ramp verfügbar sind. In einer for of Schleife werden alle Einträge in ramp mit dem value verglichen und sobald der Wert in die Schwellen passt, die entsprechende Farbe zurückgegeben. Wir schreiben die Funktion noch vor der Funktion für das Zeichnen der Stationen und testen sie mit einem Aufruf, dem wir den Wert -40 und die Farbpalette COLORS.temperature übergeben.
// Farben nach Schwellen ermitteln
let getColor = function(value, ramp) {
//console.log(value,ramp);
for (let rule of ramp) {
//console.log(rule)
if (value >= rule.min && value < rule.max) {
return rule.color;
}
}
};
console.log(getColor(-40, COLORS.temperature));
Wie erwartet, bekommen wir den Farbwert #9f80ff angezeigt. Er steht für Temperaturen zwischen -50° und -25°.
Jetzt müssen wir nur noch in pointToLayer, direkt nach let popup, die richtige Farbe für das L.divIcon ermitteln und in let color speichern.
let color = getColor(
geoJsonPoint.properties.LT,
COLORS.temperature
);
Danach können wir die Farbe als style-Attribut beim <span> Element über die CSS Regel background-color:${color} einsetzen.
icon: L.divIcon({
className: "aws-div-icon",
html: `<span style="background-color:${color}">${geoJsonPoint.properties.LT.toFixed(1)}</span>`
})
… und wird es auch nicht hunderprozentig werden, denn die Positionierung von DIV-Icons ist nicht gerade einfach. Fügen wir vor dem return des DIV-Icons mit L.marker(latlng).addTo(map) einen zweiten Marker an der selben Position ein, erkennen wir, dass die Koordinate “ungefähr” links, oben beim Text liegt. Über einen Workaround im CSS von main.css verschieben wir deshalb die Icons nach links oben:
.aws-div-icon span {
/* bestehende CSS Regeln */
display: inline-block;
transform: translate(-30%, -50%);
}
Das Verschieben der Marker bewirkt die CSS-Eigenschaft transform, deren translate Anweisung zwei Offsets in x und y Richtung erwartet. Warum wir beim Verschieben -30% für die x-Richtung verwenden müssen bleibt allerdings ein Rätsel. Immerhin liegt der Textmarker jetzt mit seinem Zentrum an der annähernd richtigen Position.
Hinweis: mit transform und der rotate Anweisung könn(t)en wir die Marker auch drehen …