/* ========================================================================== Was das Meteogramm zeigt. Hier steht alles, was man ändern will, und nichts, was man zum Zeichnen wissen muss. js/solar/meteogramm.js kennt kein Feld, keine Spur und keine Farbe beim Namen - es liest nur, was hier deklariert ist. Dasselbe Muster wie anlageKatalog.js und energieflussKatalog.js. --------------------------------------------------------------------------- So kommt eine Spur dazu 1. Spalte in ajax/meteogramm.php hinten anhängen 2. Schlüssel in SPALTEN hinten anhängen 3. Eintrag in "spuren" des passenden Feldes Sonst nichts. Hinten anhängen ist wichtig: die Stellen der bestehenden Spuren bleiben dadurch gültig. --------------------------------------------------------------------------- Das Vokabular Ein FELD ist ein waagerechter Streifen mit eigener senkrechter Achse. Alle Felder teilen sich die Zeitachse. id Kennung name Überschrift links oben im Feld hoehe Schlüssel in HOEHEN (breit/schmal) links { einheit, min?, max?, minSpanne?, gitter? } - linke Achse rechts dasselbe für die rechte Achse, oder fehlt nacht true = Tag/Nacht-Schattierung in diesem Feld zeichnen symbole { alle, mindestAbstand } für die Wettersymbolleiste, oder fehlt pfeile { spalte, alle, mindestAbstand } für die Windpfeile, oder fehlt baender Liste von BÄNDERN, vor den Spuren gezeichnet spuren Liste von SPUREN, in Zeichenreihenfolge (erste zuunterst) Eine SPUR ist eine Reihe von Werten über die Zeit. id, name Kennung; der Name steht in Legende und Tooltip spalte Schlüssel in SPALTEN achse "links" oder "rechts" art "linie" | "flaeche" | "balken" farbe Datenfarben gehören hierher, nicht ins Stylesheet breit Strichstärke bei "linie" strich z.B. "4 3" für gestrichelt nurGemessen true = nur Stunden mit gemessen = 1 nurVorhersage true = nur Stunden ohne beschriftung "minmax" = Tagesminimum und -maximum an die Kurve schreiben format Wert -> Text für den Tooltip legende true = in der Legendenzeile zeigen Ein BAND füllt eine Fläche mit veränderlicher Deckkraft - so wird das Höhenprofil der Bewölkung nachgebaut, das Open-Meteo nicht liefert. schichten je { spalte, von, bis, name } in Einheiten der rechten Achse maxDeckung Deckkraft bei 100 % ========================================================================== */ const METEOGRAMM_KATALOG = (function () { "use strict"; const komma = (z, n = 1) => Number(z).toFixed(n).replace(".", ","); const ganz = z => String(Math.round(z)); /* Die Spaltenlage einer Stundenzeile aus ajax/meteogramm.php. Steht dort im Kopfkommentar noch einmal - beide Listen müssen zueinander passen. */ const SPALTEN = { t: 0, gemessen: 1, temp: 2, regen: 3, schnee: 4, wind: 5, boe: 6, richtung: 7, strahlung: 8, wtief: 9, wmittel: 10, whoch: 11, code: 12, feuchte: 13, druck: 14, regenWkt: 15, }; /* Eine Tageszeile. */ const TAGSPALTEN = { t: 0, tmin: 1, tmax: 2, code: 3, auf: 4, unter: 5 }; /* Feldhöhen in Nutzereinheiten (= CSS-Pixel). Unter UMBRUCH gilt "schmal". Zusammen mit Achsenstreifen und Rändern ergibt "schmal" rund 345 px - das eingebettete meteoblue-Bild brauchte 500. */ const HOEHEN = { breit: { temp: 150, regen: 130, wind: 115 }, schmal: { temp: 120, regen: 100, wind: 92 }, }; const UMBRUCH = 520; /* --------------------------------------------------------- Wettersymbole WMO-Code -> Glyphe der Bootstrap-Icons, wie das ZEICHEN-Register in energiefluss.js. Die achtundzwanzig Codes fallen auf zwölf Symbole zusammen; wo es eine Nachtvariante gibt, steht sie daneben. Die Codepunkte stammen aus css/bootstrap-icons.min.css. Der Kommentar dahinter nennt das Icon - ohne ihn wäre die Zeile nicht zu lesen. */ const WETTER = { 0: { glyph: "", nacht: "", name: "klar" }, // bi-sun-fill / bi-moon-stars-fill 1: { glyph: "", nacht: "", name: "überwiegend klar" }, // dito 2: { glyph: "", nacht: "", name: "teils bewölkt" }, // bi-cloud-sun-fill / bi-cloud-moon-fill 3: { glyph: "", name: "bedeckt" }, // bi-clouds-fill 45: { glyph: "", name: "Nebel" }, // bi-cloud-fog2-fill 48: { glyph: "", name: "Reifnebel" }, // bi-cloud-fog2-fill 51: { glyph: "", name: "leichter Nieselregen" }, // bi-cloud-drizzle-fill 53: { glyph: "", name: "Nieselregen" }, // bi-cloud-drizzle-fill 55: { glyph: "", name: "starker Nieselregen" }, // bi-cloud-drizzle-fill 56: { glyph: "", name: "gefrierender Nieselregen" }, // bi-cloud-sleet-fill 57: { glyph: "", name: "starker gefrierender Nieselregen" }, // bi-cloud-sleet-fill 61: { glyph: "", name: "leichter Regen" }, // bi-cloud-rain-fill 63: { glyph: "", name: "Regen" }, // bi-cloud-rain-fill 65: { glyph: "", name: "starker Regen" }, // bi-cloud-rain-heavy-fill 66: { glyph: "", name: "gefrierender Regen" }, // bi-cloud-sleet-fill 67: { glyph: "", name: "starker gefrierender Regen" }, // bi-cloud-sleet-fill 71: { glyph: "", name: "leichter Schneefall" }, // bi-cloud-snow-fill 73: { glyph: "", name: "Schneefall" }, // bi-cloud-snow-fill 75: { glyph: "", name: "starker Schneefall" }, // bi-cloud-snow-fill 77: { glyph: "", name: "Schneegriesel" }, // bi-snow3 80: { glyph: "", name: "leichte Regenschauer" }, // bi-cloud-rain-fill 81: { glyph: "", name: "Regenschauer" }, // bi-cloud-rain-fill 82: { glyph: "", name: "heftige Regenschauer" }, // bi-cloud-rain-heavy-fill 85: { glyph: "", name: "leichte Schneeschauer" }, // bi-cloud-snow-fill 86: { glyph: "", name: "Schneeschauer" }, // bi-cloud-snow-fill 95: { glyph: "", name: "Gewitter" }, // bi-cloud-lightning-fill 96: { glyph: "", name: "Gewitter mit Hagel" }, // bi-cloud-lightning-rain-fill 99: { glyph: "", name: "schweres Gewitter mit Hagel" }, // bi-cloud-lightning-rain-fill }; /* Die Farben der Anzeige. Strukturfarben stehen im Stylesheet, Datenfarben hier - so wie bei energieflussKatalog.js. */ const FARBE = { temp: "#e5624f", tempMess: "#f0907f", strahlung: "#f0b429", regen: "#4f8fb8", schnee: "#a8cfe8", wind: "#7fb3d5", boe: "#e8a33a", wolken: "#c9d0d6", }; return { spalten: SPALTEN, tagSpalten: TAGSPALTEN, hoehen: HOEHEN, umbruch: UMBRUCH, wetter: WETTER, farbe: FARBE, /* Voreinstellung ist fünf Tage wie beim Vorbild; am Handy zwei, weil dort fünf Tage drei Pixel je Stunde bedeuten. */ zeitraeume: [ { tage: 2, name: "2 Tage" }, { tage: 5, name: "5 Tage", vorgabe: true }, { tage: 7, name: "7 Tage" }, ], zeitraumSchmal: 2, /* Wie weit der Rückblick reicht, in Stunden. Die eigene Station misst alle fünf Minuten; der Endpunkt mittelt auf Stunden. */ rueckblick: 24, /* Der Windpfeil zeigt, wohin der Wind weht. Die meteorologische Richtung sagt, woher er kommt - deshalb dreht der Renderer um 180 Grad, genau wie updateWeatherCards() in common.js. */ windPfeil: { laenge: 9, // Unter dieser Stärke verblasst der Pfeil: bei Windstille zeigt eine // Richtung ohnehin nichts an. schwach: 5, }, felder: [ { id: "temp", name: "Temperatur", hoehe: "temp", nacht: true, links: { einheit: "°C", minSpanne: 8, gitter: 4 }, // Die Strahlung teilt sich das Feld mit der Temperatur statt ein // eigenes zu bekommen: beide folgen demselben Tagesrhythmus und // derselben Tag/Nacht-Schattierung, und ein viertes Feld machte das // Meteogramm am Handy höher als das externe - also genau das // Gegenteil dessen, was es soll. Die Achse ist fest 0..1000, damit // ein trüber Tag flach bleibt und nicht auf volle Höhe gestreckt wird. rechts: { einheit: "W/m²", min: 0, max: 1000, gitter: 0 }, symbole: { alle: 3, mindestAbstand: 26 }, spuren: [ { id: "strahlung", name: "Strahlung", spalte: "strahlung", achse: "rechts", art: "flaeche", farbe: FARBE.strahlung, deckkraft: 0.16, legende: true, format: w => ganz(w) + " W/m²", }, { id: "temp", name: "Temperatur", spalte: "temp", achse: "links", art: "linie", farbe: FARBE.temp, breit: 2.4, beschriftung: "minmax", legende: true, nurVorhersage: true, format: w => komma(w, 1) + " °C", }, { // Dieselbe Spalte, aber nur die gemessenen Stunden: links vom // Jetzt-Strich steht, was die eigene Station wirklich gesehen // hat. Zwei Spuren statt einer, damit die Farbe wechseln kann, // ohne dass der Renderer von "gemessen" wissen muss. id: "tempMess", name: "gemessen", spalte: "temp", achse: "links", art: "linie", farbe: FARBE.tempMess, breit: 2.4, nurGemessen: true, legende: true, format: w => komma(w, 1) + " °C", }, ], }, { id: "regen", name: "Niederschlag und Bewölkung", hoehe: "regen", nacht: true, // minSpanne 2 mm: ohne sie füllte ein Nieselregen von 0,2 mm das // ganze Feld und sähe aus wie ein Wolkenbruch. links: { einheit: "mm/h", min: 0, minSpanne: 2, gitter: 3 }, // Die rechte Achse ist die Höhe in Kilometern - sie gehört zum // Wolkenband, nicht zu einer Spur. rechts: { einheit: "km", min: 0, max: 14, ticks: [0, 2, 7, 14] }, baender: [ { id: "wolken", name: "Bewölkung", achse: "rechts", farbe: FARBE.wolken, maxDeckung: 0.42, // Open-Meteo kennt drei Schichten statt eines Profils. Die // Grenzen sind die üblichen meteorologischen: tiefe Wolken bis // 2 km, mittelhohe bis 7 km, hohe darüber. schichten: [ { spalte: "wtief", von: 0, bis: 2, name: "tief" }, { spalte: "wmittel", von: 2, bis: 7, name: "mittel" }, { spalte: "whoch", von: 7, bis: 14, name: "hoch" }, ], }, ], spuren: [ { id: "regen", name: "Niederschlag", spalte: "regen", achse: "links", art: "balken", farbe: FARBE.regen, legende: true, format: w => komma(w, 1) + " mm/h", }, { id: "schnee", name: "Schnee", spalte: "schnee", achse: "links", art: "balken", farbe: FARBE.schnee, legende: true, // Schnee kommt in cm, die Achse rechnet in mm Wasser. Die // Faustregel ist ein Zentimeter Neuschnee je Millimeter Wasser. skala: w => w * 1, format: w => komma(w, 1) + " cm", }, ], }, { id: "wind", name: "Wind", hoehe: "wind", links: { einheit: "km/h", min: 0, minSpanne: 20, gitter: 3 }, pfeile: { spalte: "richtung", staerke: "wind", alle: 3, mindestAbstand: 16 }, spuren: [ { id: "boe", name: "Böen", spalte: "boe", achse: "links", art: "linie", farbe: FARBE.boe, breit: 1.6, strich: "4 3", legende: true, format: w => komma(w, 1) + " km/h", }, { id: "wind", name: "Wind", spalte: "wind", achse: "links", art: "linie", farbe: FARBE.wind, breit: 2.2, legende: true, format: w => komma(w, 1) + " km/h", }, ], }, ], }; })();