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 …