diff --git a/css/solar.css b/css/solar.css index 270b284..557e83c 100644 --- a/css/solar.css +++ b/css/solar.css @@ -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; +} diff --git a/js/solar/homeMQTT.js b/js/solar/homeMQTT.js index a2d6a89..bf3ace1 100644 --- a/js/solar/homeMQTT.js +++ b/js/solar/homeMQTT.js @@ -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))); } /** diff --git a/restricted/roomControls.php b/restricted/roomControls.php index c0652ae..44d26d9 100644 --- a/restricted/roomControls.php +++ b/restricted/roomControls.php @@ -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 "
" + . " data-param='" . intval($param["id"]) . "' data-rolle='" . $rolle . "'>" . "" . htmlspecialchars($titel) . "" . "" . htmlspecialchars($oben) . "" . "
" . reglerFeld($min, $max, $wert, "%", $titel) . "
" . "" . htmlspecialchars($unten) . "" - . "" . $wert . "%" . "
"; } /** - * 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 = ""; } /** Kippschalter mit dem Stand, den das Geraet zuletzt gemeldet hat. */ @@ -434,18 +449,18 @@ function zeichneBeschattung($d) } $html .= ""; } + // 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 .= "
" - . senkrechterRegler($neigung, $neigung["params"][0], $standNeigung, - "Neigung", "auf", "zu") - . lamellenBild() - . "
"; + $html .= senkrechterRegler($neigung, $neigung["params"][0], $standNeigung, + "Neigung", "auf", "zu", "neigung"); } $html .= mehrMenue($rest); return $html . "" . karteZu();