Raum-Modal: Gruppen als Tabs, Jalousien senkrecht bedienen

Die Gruppenueberschriften sind Tabs geworden, Beschattung zuerst - das ist
es, was man in einem Raum am haeufigsten anfasst. Vorher scrollte man an
drei Rollladen vorbei, um zum Licht zu kommen. Bei nur einer Gruppe bleibt
die Leiste weg; auf schmalen Schirmen scrollt sie seitwaerts, statt die
Namen umzubrechen.

Bei den Jalousien stehen Auf, Stop und Zu jetzt untereinander - so zeigen
die Knoepfe in die Richtung, in die sie fahren. Die Hoehe daneben ist ein
senkrechter Regler mit "oben" und "unten" an den Enden: der Griff steht
dort, wo der Rollladen steht, und niemand muss "100 %" uebersetzen.

Die Neigung hat ein Bild dazubekommen. "30 %" oder "70 %" sagt nicht, ob
man noch hinaussieht; vier Streifen sagen es. Gezeichnet wird die Hoehe,
die eine gekippte Lamelle von vorn zeigt (w * sin(Winkel)) - bei "auf"
sieht man nur ihre Kante und viel Luft dazwischen, bei "zu" deckt sie den
Abstand zur naechsten vollstaendig ab. Genau das, was das Licht abhaelt.

Die Regler faerben ihre Bahn jetzt mit, wie es der Temperaturregler seit
jeher tut - dieselbe Eigenschaft --background-size, nur beim senkrechten
von oben nach unten.

css/solar.css hatte gemischte Zeilenenden und ist dabei durchgehend auf LF
gebracht worden; das erklaert den grossen Diff bei kleiner Aenderung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-31 21:38:09 +02:00
co-authored by Claude Opus 5
parent 17f972d081
commit f6e0414866
4 changed files with 403 additions and 143 deletions
+53 -6
View File
@@ -226,14 +226,13 @@ function switchFloor(floor){
k.addEventListener("click", () => schalte(k));
});
// Schieberegler: waehrend des Ziehens nur die Beschriftung, geschickt
// wird erst beim Loslassen. Sonst bekaeme eine Jalousie bei jedem Pixel
// ein neues Ziel und kaeme aus dem Anfahren nicht mehr heraus.
// Schieberegler: waehrend des Ziehens nur die Anzeige, geschickt wird
// erst beim Loslassen. Sonst bekaeme eine Jalousie bei jedem Pixel ein
// neues Ziel und kaeme aus dem Anfahren nicht mehr heraus.
koerper.querySelectorAll(".raum-regler").forEach(regler => {
const schieber = regler.querySelector("input[type=range]");
const anzeige = regler.querySelector(".raum-regler-wert");
const einheit = schieber.dataset.einheit || "";
schieber.addEventListener("input", () => { anzeige.textContent = schieber.value + einheit; });
reglerAnzeigen(regler);
schieber.addEventListener("input", () => reglerAnzeigen(regler));
schieber.addEventListener("change", () => {
const params = {};
params[regler.dataset.param] = schieber.value;
@@ -280,6 +279,54 @@ function switchFloor(floor){
});
}
/**
* Anzeige, gefuellte Bahn und Lamellenbild eines Reglers nachziehen.
*
* An den Endstellungen steht ein Wort statt der Zahl: "unten" liest sich
* ohne Umweg, "100 %" muss man erst uebersetzen. Dazwischen bleibt es bei
* der Prozentzahl - fuer halb heruntergefahren gibt es kein Wort.
*/
function reglerAnzeigen(regler) {
const schieber = regler.querySelector("input[type=range]");
const anzeige = regler.querySelector(".raum-regler-wert");
const wert = Number(schieber.value);
if (anzeige) {
const worte = regler.dataset.worte ? JSON.parse(regler.dataset.worte) : null;
anzeige.textContent = (worte && worte[wert] !== undefined)
? worte[wert]
: wert + (schieber.dataset.einheit || "");
}
// Der gefuellte Anteil der Bahn - dieselbe Eigenschaft, aus der auch
// bindModalSlider() in common.js den Temperaturregler faerbt.
const min = Number(schieber.min);
const max = Number(schieber.max);
schieber.style.setProperty("--background-size",
((wert - min) * 100 / (max - min)) + "%");
lamellenZeichnen(regler.closest(".raum-neigung-block"), wert, min, max);
}
/**
* Die Lamellen zur Neigung zeichnen.
*
* Gezeichnet wird die Hoehe, die eine gekippte Lamelle von vorn zeigt:
* w * sin(Winkel). Bei 0 % steht sie waagerecht und man sieht nur ihre
* Kante, bei 100 % steht sie quer und deckt den Abstand zur naechsten
* vollstaendig ab - genau das, was das Licht abhaelt.
*/
function lamellenZeichnen(block, wert, min, max) {
if (!block) return;
const anteil = (wert - min) / (max - min);
const hoehe = Math.max(1.6, 11 * Math.sin(anteil * Math.PI / 2));
block.querySelectorAll(".raum-lamelle").forEach(lamelle => {
const mitte = Number(lamelle.dataset.mitte);
lamelle.setAttribute("height", hoehe);
lamelle.setAttribute("y", mitte - hoehe / 2);
});
}
/**
* Die Ist-Werte im Heizungsteil aus dem laufenden MQTT-Strom fuellen.
*