Raum-Modal: Fensterbild zeigt Hoehe und Neigung, Regler nach rechts

Die Regler standen neben den Fahrknoepfen - beim Antippen von "Auf" fand
der Daumen leicht den Schieber daneben. Jetzt stehen sie rechts aussen,
zwischen ihnen und den Knoepfen liegt das Fensterbild.

Das Bild zeigt jetzt beides. Die Hoehe schneidet ab: gezeichnet wird nur
der Teil des Fensters, den die Jalousie bedeckt, mit der Endschiene an
seiner Unterkante; darunter sieht man hinaus. Die Neigung bestimmt wie
bisher, wie dick eine Lamelle von vorn erscheint. Ein Rollladen ohne
Neigung bekommt volle Lamellenhoehe - er ist ja ein geschlossener Panzer.

Die Prozentzahl unter den Reglern ist weg; die Bahn ist dafuer von 5 auf
6,5 rem gewachsen. Was der Regler bewirkt, zeigt das Bild ohnehin besser
als eine Zahl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-31 21:59:52 +02:00
co-authored by Claude Opus 5
parent e7fd7715ef
commit 18557021b0
3 changed files with 87 additions and 48 deletions
+10 -12
View File
@@ -277,14 +277,10 @@ input[type='range']::-webkit-slider-runnable-track {
align-items: stretch;
gap: 0.6rem;
}
/* Neigungsregler und Lamellenbild gehoeren zusammen: das Bild sagt, was der
Regler daneben bedeutet, und laeuft beim Ziehen mit. */
.raum-jalousie .raum-neigung-block {
display: flex;
align-items: stretch;
gap: 0.4rem;
/* Das Fensterbild nimmt den Platz zwischen Knoepfen und Reglern. */
.raum-jalousie .raum-lamellen {
flex: 1 1 auto;
min-width: 0;
min-width: 2.5rem;
}
.raum-jalousie .dropdown {
align-self: flex-start;
@@ -325,14 +321,14 @@ input[type='range']::-webkit-slider-runnable-track {
.raum-senkrecht {
position: relative;
width: 1.6rem;
height: 5rem;
height: 6.5rem;
margin: 0.1rem 0;
}
#roomView .raum-senkrecht input[type='range'] {
position: absolute;
top: 50%;
left: 50%;
width: 5rem; /* = Hoehe des Kastens, die Laenge der Bahn */
width: 6.5rem; /* = Hoehe des Kastens, die Laenge der Bahn */
height: 1.6rem; /* = Breite des Kastens, die Flaeche zum Treffen */
transform: translate(-50%, -50%) rotate(90deg);
touch-action: none;
@@ -350,10 +346,8 @@ input[type='range']::-webkit-slider-runnable-track {
aneinanderliegend heisst geschlossen. */
.raum-lamellen {
display: block;
flex: 1 1 auto;
min-width: 2.5rem;
align-self: center;
height: 5rem;
height: 6.9rem;
/* Der Rahmen macht aus dem Streifen ein Fenster - ohne ihn liest sich das
geschlossene Bild wie eine zweite Reglerbahn. */
background: rgba(0, 120, 143, 0.14);
@@ -367,3 +361,7 @@ input[type='range']::-webkit-slider-runnable-track {
stroke-width: 0.6;
vector-effect: non-scaling-stroke;
}
.raum-endschiene {
fill: currentColor;
opacity: 0.85;
}
+42 -16
View File
@@ -229,6 +229,7 @@ function switchFloor(floor){
// 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-jalousie").forEach(lamellenZeichnen);
koerper.querySelectorAll(".raum-regler").forEach(regler => {
const schieber = regler.querySelector("input[type=range]");
reglerAnzeigen(regler);
@@ -283,8 +284,8 @@ function switchFloor(floor){
* Anzeige, gefuellte Bahn und Lamellenbild eines Reglers nachziehen.
*
* Was 0 % und 100 % bedeuten, steht bei den senkrechten Reglern als Wort
* an ihren Enden ("oben"/"unten", "auf"/"zu"); die Anzeige braucht deshalb
* nur noch die Zahl, und die ist beim Ziehen das Interessante.
* an ihren Enden ("oben"/"unten", "auf"/"zu"); eine Zahl steht dort nicht
* mehr - das Bild daneben zeigt beim Ziehen mehr als sie.
*/
function reglerAnzeigen(regler) {
const schieber = regler.querySelector("input[type=range]");
@@ -302,28 +303,53 @@ function switchFloor(floor){
schieber.style.setProperty("--background-size",
((wert - min) * 100 / (max - min)) + "%");
lamellenZeichnen(regler.closest(".raum-neigung-block"), wert, min, max);
lamellenZeichnen(regler.closest(".raum-jalousie"));
}
/** Der Stand eines der beiden Regler einer Jalousie, als Anteil 0..1. */
function reglerAnteil(jalousie, rolle, ersatz) {
const schieber = jalousie.querySelector("[data-rolle=" + rolle + "] input[type=range]");
if (!schieber) return ersatz;
const min = Number(schieber.min);
return (Number(schieber.value) - min) / (Number(schieber.max) - min);
}
/**
* Die Lamellen zur Neigung zeichnen.
* Das Fenster zeichnen, wie die Jalousie davor gerade steht.
*
* 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. Der Abstand von
* Mitte zu Mitte ist 10, die Lamelle 11 tief: ab etwa 65 % schliesst
* Zwei Zahlen in einem Bild. Die Hoehe schneidet ab - gezeichnet wird nur
* der Teil des Fensters, den die Jalousie bedeckt, mit der Endschiene an
* seiner Unterkante. Die Neigung bestimmt, wie dick eine Lamelle von vorn
* erscheint: 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. Von Mitte zu Mitte
* sind es 10 Einheiten, die Lamelle ist 11 tief; ab etwa 65 % schliesst
* das Bild, so wie es die Jalousie auch tut.
*
* Ein Rollladen ohne Neigung bekommt volle Lamellenhoehe - er ist ja ein
* geschlossener Panzer.
*/
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 => {
function lamellenZeichnen(jalousie) {
if (!jalousie) return;
const bild = jalousie.querySelector(".raum-lamellen");
if (!bild) return;
const hoch = bild.viewBox.baseVal.height;
const abdeckung = hoch * reglerAnteil(jalousie, "position", 1);
const kippung = reglerAnteil(jalousie, "neigung", 1);
const dicke = Math.max(1.6, 11 * Math.sin(kippung * Math.PI / 2));
bild.querySelector(".raum-abdeckung").setAttribute("height", abdeckung);
bild.querySelectorAll(".raum-lamelle").forEach(lamelle => {
const mitte = Number(lamelle.dataset.mitte);
lamelle.setAttribute("height", hoehe);
lamelle.setAttribute("y", mitte - hoehe / 2);
lamelle.setAttribute("height", dicke);
lamelle.setAttribute("y", mitte - dicke / 2);
});
// Die Endschiene sitzt auf der Unterkante und bleibt im Bild, auch wenn
// die Jalousie ganz oben steht.
const schiene = bild.querySelector(".raum-endschiene");
const dick = schiene.height.baseVal.value;
schiene.setAttribute("y", Math.max(0, Math.min(hoch - dick, abdeckung - dick)));
}
/**
+35 -20
View File
@@ -283,38 +283,53 @@ function reglerFeld($min, $max, $wert, $einheit, $beschriftung = "")
* bewegt sich in seinen eigenen Koordinaten waagerecht, wird von jedem
* Browser unterstuetzt und traegt dieselbe Gestaltung wie die liegenden.
*/
function senkrechterRegler($cmd, $param, $wert, $titel, $oben, $unten)
function senkrechterRegler($cmd, $param, $wert, $titel, $oben, $unten, $rolle)
{
$min = reglerMin($param);
$max = reglerMax($param);
$wert = reglerWert($wert, $min, $max);
// Keine Prozentzahl darunter: was der Regler bewirkt, zeigt das
// Lamellenbild daneben, und die gesparte Zeile macht die Bahn laenger.
return "<div class='raum-regler raum-spalte' data-cmd='" . intval($cmd["id"]) . "'"
. " data-param='" . intval($param["id"]) . "'>"
. " data-param='" . intval($param["id"]) . "' data-rolle='" . $rolle . "'>"
. "<span class='raum-name'>" . htmlspecialchars($titel) . "</span>"
. "<span class='raum-ende'>" . htmlspecialchars($oben) . "</span>"
. "<div class='raum-senkrecht'>" . reglerFeld($min, $max, $wert, "%", $titel) . "</div>"
. "<span class='raum-ende'>" . htmlspecialchars($unten) . "</span>"
. "<span class='raum-regler-wert small fw-semibold'>" . $wert . "%</span>"
. "</div>";
}
/**
* Die sechs Lamellen neben dem Neigungsregler.
* Das Fenster, wie die Jalousie davor gerade steht.
*
* Bei 30 % oder 70 % sagt die Zahl nicht, ob man noch hinaussieht. Die
* Streifen zeigen es: schmal mit Luft dazwischen heisst offen, geschlossen
* liegen sie aneinander. Gezeichnet wird die Hoehe, die eine gekippte
* Lamelle von vorn zeigt - genau das, was das Licht abhaelt. Die Hoehe setzt
* lamellenZeichnen() in js/solar/homeMQTT.js.
* Zwei Zahlen in einem Bild: wie weit sie heruntergefahren ist und wie die
* Lamellen stehen. Weder "60 %" noch "30 %" sagt, ob man noch hinaussieht -
* das Bild sagt es.
*
* Die Hoehe schneidet ab: gezeichnet wird nur der Teil des Fensters, den die
* Jalousie bedeckt, mit der Endschiene an seiner Unterkante. Die Neigung
* bestimmt, wie dick eine Lamelle von vorn erscheint - w * sin(Winkel),
* genau das, was das Licht abhaelt. Beides setzt lamellenZeichnen() in
* js/solar/homeMQTT.js.
*
* Die Kennung des Beschnitts traegt die Geraetenummer: in einem Raum haengen
* mehrere dieser Bilder, und url(#...) findet sonst immer dasselbe.
*/
function lamellenBild()
function lamellenBild($actorId)
{
$html = "<svg class='raum-lamellen' viewBox='0 0 100 60' preserveAspectRatio='none' aria-hidden='true'>";
$schnitt = "lamellen" . intval($actorId);
$html = "<svg class='raum-lamellen' viewBox='0 0 100 60' preserveAspectRatio='none' aria-hidden='true'>"
. "<defs><clipPath id='" . $schnitt . "'>"
. "<rect class='raum-abdeckung' x='0' y='0' width='100' height='60'></rect>"
. "</clipPath></defs>"
. "<g clip-path='url(#" . $schnitt . ")'>";
foreach ([5, 15, 25, 35, 45, 55] as $mitte) {
$html .= "<rect class='raum-lamelle' x='0' width='100' data-mitte='" . $mitte . "'"
. " y='" . ($mitte - 1) . "' height='2'></rect>";
}
return $html . "</svg>";
return $html . "</g>"
. "<rect class='raum-endschiene' x='0' y='57' width='100' height='3'></rect>"
. "</svg>";
}
/** Kippschalter mit dem Stand, den das Geraet zuletzt gemeldet hat. */
@@ -434,18 +449,18 @@ function zeichneBeschattung($d)
}
$html .= "</div>";
}
// Erst das Bild, dann die Regler: neben den Fahrknoepfen faende der
// Daumen sonst beim Antippen gleich einen Schieber.
if ($position || $neigung) {
$html .= lamellenBild($d["id"]);
}
if ($position) {
$html .= senkrechterRegler($position, $position["params"][0], $standPos,
"Position", "oben", "unten");
"Position", "oben", "unten", "position");
}
if ($neigung) {
// Regler und Lamellenbild bilden ein Paar: das Bild sagt, was der
// Regler daneben bedeutet, und laeuft beim Ziehen mit.
$html .= "<div class='raum-neigung-block'>"
. senkrechterRegler($neigung, $neigung["params"][0], $standNeigung,
"Neigung", "auf", "zu")
. lamellenBild()
. "</div>";
$html .= senkrechterRegler($neigung, $neigung["params"][0], $standNeigung,
"Neigung", "auf", "zu", "neigung");
}
$html .= mehrMenue($rest);
return $html . "</div>" . karteZu();