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:
+1
-13
@@ -133,19 +133,7 @@ if (!$gruppen && !$hatThermostat) {
|
|||||||
. "Das geht über das Haus-Symbol in der Karte „Automatismen“.</p>";
|
. "Das geht über das Haus-Symbol in der Karte „Automatismen“.</p>";
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (raumGruppenTitel() as $form => $titel) {
|
echo zeichneGruppen($gruppen);
|
||||||
if (empty($gruppen[$form])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Eine einzelne Lampe braucht keine Ueberschrift "Licht" - der Name der
|
|
||||||
// Lampe steht direkt darunter. Ueberschriften ordnen erst ab zwei.
|
|
||||||
if (count($gruppen[$form]) > 1) {
|
|
||||||
echo gruppenTitel($titel[0], $titel[1]);
|
|
||||||
}
|
|
||||||
foreach ($gruppen[$form] as $d) {
|
|
||||||
echo zeichneGeraet($d, $form);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "<div id='roomFeedback' class='small mt-2'></div>";
|
echo "<div id='roomFeedback' class='small mt-2'></div>";
|
||||||
echo "</div>";
|
echo "</div>";
|
||||||
|
|||||||
+97
-12
@@ -118,17 +118,21 @@ input[type='range']::-webkit-slider-runnable-track {
|
|||||||
Erzeugt von restricted/roomControls.php, verdrahtet in js/solar/homeMQTT.js.
|
Erzeugt von restricted/roomControls.php, verdrahtet in js/solar/homeMQTT.js.
|
||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Ueberschrift einer Geraetegruppe (Beschattung, Licht, ...). Klein und
|
/* Die Geraetegruppen als Tabs. Auf einem Handy passen fuenf Beschriftungen
|
||||||
ruhig - sie ordnet, sie soll nicht mit den Geraeten um Aufmerksamkeit
|
nicht nebeneinander - dann scrollt die Leiste seitwaerts, statt die Namen
|
||||||
ringen. */
|
umzubrechen. */
|
||||||
.raum-gruppe {
|
.raum-tabs {
|
||||||
font-size: 0.75rem;
|
overflow-x: auto;
|
||||||
text-transform: uppercase;
|
overflow-y: hidden;
|
||||||
letter-spacing: 0.05em;
|
scrollbar-width: none;
|
||||||
margin: 0.75rem 0 0.35rem;
|
|
||||||
}
|
}
|
||||||
.raum-gruppe:first-child {
|
.raum-tabs::-webkit-scrollbar {
|
||||||
margin-top: 0;
|
display: none;
|
||||||
|
}
|
||||||
|
.raum-tabs .nav-link {
|
||||||
|
padding: 0.25rem 0.6rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Waehrend ein Kommando unterwegs ist. Ein "Zu" an einer Jalousie dauert
|
/* Waehrend ein Kommando unterwegs ist. Ein "Zu" an einer Jalousie dauert
|
||||||
@@ -190,12 +194,93 @@ input[type='range']::-webkit-slider-runnable-track {
|
|||||||
.raum-wert-einheit {
|
.raum-wert-einheit {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
opacity: 0.7;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
.raum-wert-name {
|
.raum-wert-name {
|
||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
opacity: 0.7;
|
opacity: 0.6;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
Raum-Modal: Jalousien
|
||||||
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Fahrknoepfe, Hoehe und Neigung nebeneinander. Die Neigung nimmt den Rest -
|
||||||
|
sie ist die einzige der drei Spalten, die von Breite profitiert. */
|
||||||
|
.raum-jalousie {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
.raum-jalousie .raum-neigung-block {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.raum-jalousie .dropdown {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auf, Stop, Zu untereinander - die Knoepfe zeigen in die Richtung, in die
|
||||||
|
sie fahren. Schmal, weil nur Symbole darin stehen. */
|
||||||
|
.raum-fahrt {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.raum-fahrt .btn {
|
||||||
|
padding: 0.2rem 0.55rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die Hoehe als senkrechter Regler: der Griff steht dort, wo der Rollladen
|
||||||
|
steht. writing-mode ist der Weg, den Chrome und Firefox heute gehen -
|
||||||
|
slider-vertical war nie standardisiert und ist inzwischen entfernt. */
|
||||||
|
.raum-position {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.1rem;
|
||||||
|
}
|
||||||
|
.raum-position input[type='range'] {
|
||||||
|
writing-mode: vertical-rl;
|
||||||
|
width: 1.2rem;
|
||||||
|
height: 4.5rem;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
/* Die gefuellte Bahn laeuft hier von oben nach unten mit - "voll" heisst
|
||||||
|
heruntergefahren. */
|
||||||
|
.raum-position input[type='range']::-webkit-slider-runnable-track {
|
||||||
|
background: linear-gradient(to bottom, #00788F, #00788F), #D7D7D7;
|
||||||
|
background-size: 100% var(--background-size, 0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die Endstellungen in Worten statt in Prozent. */
|
||||||
|
.raum-ende {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
opacity: 0.65;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Die Lamellen zur Neigung. Ihre Hoehe setzt lamellenZeichnen() in
|
||||||
|
js/solar/homeMQTT.js - schmal mit Luft dazwischen heisst offen,
|
||||||
|
aneinanderliegend heisst geschlossen. */
|
||||||
|
.raum-lamellen {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 1.8rem;
|
||||||
|
margin: 0.1rem 0;
|
||||||
|
/* 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);
|
||||||
|
border: 1px solid rgba(128, 128, 128, 0.35);
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
}
|
||||||
|
.raum-lamelle {
|
||||||
|
fill: currentColor;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|||||||
+53
-6
@@ -226,14 +226,13 @@ function switchFloor(floor){
|
|||||||
k.addEventListener("click", () => schalte(k));
|
k.addEventListener("click", () => schalte(k));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Schieberegler: waehrend des Ziehens nur die Beschriftung, geschickt
|
// Schieberegler: waehrend des Ziehens nur die Anzeige, geschickt wird
|
||||||
// wird erst beim Loslassen. Sonst bekaeme eine Jalousie bei jedem Pixel
|
// erst beim Loslassen. Sonst bekaeme eine Jalousie bei jedem Pixel ein
|
||||||
// ein neues Ziel und kaeme aus dem Anfahren nicht mehr heraus.
|
// neues Ziel und kaeme aus dem Anfahren nicht mehr heraus.
|
||||||
koerper.querySelectorAll(".raum-regler").forEach(regler => {
|
koerper.querySelectorAll(".raum-regler").forEach(regler => {
|
||||||
const schieber = regler.querySelector("input[type=range]");
|
const schieber = regler.querySelector("input[type=range]");
|
||||||
const anzeige = regler.querySelector(".raum-regler-wert");
|
reglerAnzeigen(regler);
|
||||||
const einheit = schieber.dataset.einheit || "";
|
schieber.addEventListener("input", () => reglerAnzeigen(regler));
|
||||||
schieber.addEventListener("input", () => { anzeige.textContent = schieber.value + einheit; });
|
|
||||||
schieber.addEventListener("change", () => {
|
schieber.addEventListener("change", () => {
|
||||||
const params = {};
|
const params = {};
|
||||||
params[regler.dataset.param] = schieber.value;
|
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.
|
* Die Ist-Werte im Heizungsteil aus dem laufenden MQTT-Strom fuellen.
|
||||||
*
|
*
|
||||||
|
|||||||
+164
-24
@@ -137,18 +137,72 @@ function bedienform($d)
|
|||||||
return "sonstiges";
|
return "sonstiges";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ueberschriften der Gruppen, in der Reihenfolge, in der sie erscheinen. */
|
/**
|
||||||
|
* Die Gruppen in der Reihenfolge, in der ihre Tabs erscheinen.
|
||||||
|
*
|
||||||
|
* Beschattung zuerst: das ist es, was man in einem Raum am haeufigsten
|
||||||
|
* anfasst. Messwerte zuletzt - die schaut man an, man bedient sie nicht.
|
||||||
|
*/
|
||||||
function raumGruppenTitel()
|
function raumGruppenTitel()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"beschattung" => ["Beschattung", "bi-blinds"],
|
"beschattung" => ["Beschattung", "bi-blinds"],
|
||||||
"licht" => ["Licht", "bi-lightbulb"],
|
"licht" => ["Licht", "bi-lightbulb"],
|
||||||
"schalter" => ["Schalten", "bi-toggle-on"],
|
"schalter" => ["Schalten", "bi-toggle-on"],
|
||||||
"sonstiges" => ["Weitere Geräte", "bi-sliders"],
|
"sonstiges" => ["Geräte", "bi-sliders"],
|
||||||
"messwerte" => ["Messwerte", "bi-speedometer2"],
|
"messwerte" => ["Messwerte", "bi-speedometer2"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Geraetegruppen als Tabs.
|
||||||
|
*
|
||||||
|
* Vorher standen sie untereinander, und man scrollte an drei Rollladen
|
||||||
|
* vorbei, um zum Licht zu kommen. Bei nur einer Gruppe bleibt die Leiste
|
||||||
|
* weg - ein einzelner Tab beschriftet nur sich selbst.
|
||||||
|
*/
|
||||||
|
function zeichneGruppen($gruppen)
|
||||||
|
{
|
||||||
|
$vorhanden = [];
|
||||||
|
foreach (raumGruppenTitel() as $form => $titel) {
|
||||||
|
if (!empty($gruppen[$form])) {
|
||||||
|
$vorhanden[$form] = $titel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$vorhanden) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = "";
|
||||||
|
if (count($vorhanden) > 1) {
|
||||||
|
$html .= "<ul class='nav nav-pills flex-nowrap gap-1 mb-2 raum-tabs' role='tablist'>";
|
||||||
|
$erster = true;
|
||||||
|
foreach ($vorhanden as $form => $titel) {
|
||||||
|
$html .= "<li class='nav-item' role='presentation'>"
|
||||||
|
. "<button class='nav-link" . ($erster ? " active" : "") . "' type='button'"
|
||||||
|
. " data-bs-toggle='tab' data-bs-target='#raumtab-" . $form . "' role='tab'>"
|
||||||
|
. "<i class='bi " . $titel[1] . "'></i>"
|
||||||
|
. "<span class='ms-1'>" . htmlspecialchars($titel[0]) . "</span>"
|
||||||
|
. "</button></li>";
|
||||||
|
$erster = false;
|
||||||
|
}
|
||||||
|
$html .= "</ul>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= "<div class='tab-content'>";
|
||||||
|
$erster = true;
|
||||||
|
foreach ($vorhanden as $form => $titel) {
|
||||||
|
$html .= "<div class='tab-pane fade" . ($erster ? " show active" : "") . "'"
|
||||||
|
. " id='raumtab-" . $form . "' role='tabpanel'>";
|
||||||
|
foreach ($gruppen[$form] as $d) {
|
||||||
|
$html .= zeichneGeraet($d, $form);
|
||||||
|
}
|
||||||
|
$html .= "</div>";
|
||||||
|
$erster = false;
|
||||||
|
}
|
||||||
|
return $html . "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Bausteine
|
// Bausteine
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -178,20 +232,109 @@ function karteZu()
|
|||||||
*/
|
*/
|
||||||
function reglerZeile($titel, $cmd, $param, $wert, $einheit = "%")
|
function reglerZeile($titel, $cmd, $param, $wert, $einheit = "%")
|
||||||
{
|
{
|
||||||
$min = $param["min"] === null ? 0 : intval($param["min"]);
|
$min = reglerMin($param);
|
||||||
$max = $param["max"] === null ? 100 : intval($param["max"]);
|
$max = reglerMax($param);
|
||||||
$wert = $wert === null || $wert === "" ? $min : intval($wert);
|
$wert = reglerWert($wert, $min, $max);
|
||||||
$wert = max($min, min($max, $wert));
|
|
||||||
return "<div class='raum-regler' data-cmd='" . intval($cmd["id"]) . "'"
|
return "<div class='raum-regler' data-cmd='" . intval($cmd["id"]) . "'"
|
||||||
. " data-param='" . intval($param["id"]) . "'>"
|
. " data-param='" . intval($param["id"]) . "'>"
|
||||||
. "<div class='d-flex justify-content-between small'>"
|
. "<div class='d-flex justify-content-between small'>"
|
||||||
. "<span>" . htmlspecialchars($titel) . "</span>"
|
. "<span>" . htmlspecialchars($titel) . "</span>"
|
||||||
. "<span class='raum-regler-wert fw-semibold'>" . $wert . $einheit . "</span></div>"
|
. "<span class='raum-regler-wert fw-semibold'>" . $wert . $einheit . "</span></div>"
|
||||||
. "<input type='range' class='form-range range-color-track' min='" . $min . "' max='" . $max . "'"
|
. reglerFeld($min, $max, $wert, $einheit)
|
||||||
. " step='1' value='" . $wert . "' data-einheit='" . htmlspecialchars($einheit, ENT_QUOTES) . "'>"
|
|
||||||
. "</div>";
|
. "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reglerMin($param)
|
||||||
|
{
|
||||||
|
return $param["min"] === null ? 0 : intval($param["min"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reglerMax($param)
|
||||||
|
{
|
||||||
|
return $param["max"] === null ? 100 : intval($param["max"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reglerWert($wert, $min, $max)
|
||||||
|
{
|
||||||
|
$wert = $wert === null || $wert === "" ? $min : intval($wert);
|
||||||
|
return max($min, min($max, $wert));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reglerFeld($min, $max, $wert, $einheit)
|
||||||
|
{
|
||||||
|
return "<input type='range' class='form-range range-color-track' min='" . $min . "' max='" . $max . "'"
|
||||||
|
. " step='1' value='" . $wert . "' data-einheit='" . htmlspecialchars($einheit, ENT_QUOTES) . "'>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die beiden Endstellungen in Worten.
|
||||||
|
*
|
||||||
|
* "Position 100 %" muss man uebersetzen, "unten" nicht. Dazwischen bleibt es
|
||||||
|
* bei der Zahl - fuer halb heruntergefahren gibt es kein Wort. Ausgewertet
|
||||||
|
* wird das Attribut in raumBedienungAktivieren(), js/solar/homeMQTT.js.
|
||||||
|
*/
|
||||||
|
function worteAttribut($beiNull, $beiHundert)
|
||||||
|
{
|
||||||
|
return " data-worte='" . htmlspecialchars(
|
||||||
|
json_encode([0 => $beiNull, 100 => $beiHundert], JSON_UNESCAPED_UNICODE), ENT_QUOTES) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Hoehe als senkrechter Regler - oben ist oben.
|
||||||
|
*
|
||||||
|
* Einen waagerechten Schieber fuer eine Bewegung, die hoch und runter geht,
|
||||||
|
* muss man erst uebersetzen; senkrecht steht der Griff dort, wo der Rollladen
|
||||||
|
* steht.
|
||||||
|
*/
|
||||||
|
function positionsRegler($cmd, $param, $wert)
|
||||||
|
{
|
||||||
|
$min = reglerMin($param);
|
||||||
|
$max = reglerMax($param);
|
||||||
|
$wert = reglerWert($wert, $min, $max);
|
||||||
|
return "<div class='raum-regler raum-position' data-cmd='" . intval($cmd["id"]) . "'"
|
||||||
|
. " data-param='" . intval($param["id"]) . "'" . worteAttribut("oben", "unten") . ">"
|
||||||
|
. "<span class='raum-ende'>oben</span>"
|
||||||
|
. reglerFeld($min, $max, $wert, "%")
|
||||||
|
. "<span class='raum-ende'>unten</span>"
|
||||||
|
. "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Lamellenstellung mit einem Bild daneben.
|
||||||
|
*
|
||||||
|
* Bei 30 % oder 70 % sagt die Zahl nicht, ob man noch hinaussieht. Die vier
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
function neigungsRegler($cmd, $param, $wert)
|
||||||
|
{
|
||||||
|
$min = reglerMin($param);
|
||||||
|
$max = reglerMax($param);
|
||||||
|
$wert = reglerWert($wert, $min, $max);
|
||||||
|
return "<div class='raum-regler raum-neigung raum-neigung-block'"
|
||||||
|
. " data-cmd='" . intval($cmd["id"]) . "'"
|
||||||
|
. " data-param='" . intval($param["id"]) . "'" . worteAttribut("auf", "zu") . ">"
|
||||||
|
. "<div class='d-flex justify-content-between small'>"
|
||||||
|
. "<span>Neigung</span>"
|
||||||
|
. "<span class='raum-regler-wert fw-semibold'>" . $wert . "%</span></div>"
|
||||||
|
. lamellenBild()
|
||||||
|
. reglerFeld($min, $max, $wert, "%")
|
||||||
|
. "<div class='d-flex justify-content-between raum-ende'><span>auf</span><span>zu</span></div>"
|
||||||
|
. "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Die vier Lamellen. Ihre Hoehe setzt der Browser, siehe homeMQTT.js. */
|
||||||
|
function lamellenBild()
|
||||||
|
{
|
||||||
|
$html = "<svg class='raum-lamellen' viewBox='0 0 100 40' preserveAspectRatio='none' aria-hidden='true'>";
|
||||||
|
foreach ([5, 15, 25, 35] as $mitte) {
|
||||||
|
$html .= "<rect class='raum-lamelle' x='0' width='100' data-mitte='" . $mitte . "'"
|
||||||
|
. " y='" . ($mitte - 1) . "' height='2'></rect>";
|
||||||
|
}
|
||||||
|
return $html . "</svg>";
|
||||||
|
}
|
||||||
|
|
||||||
/** Kippschalter mit dem Stand, den das Geraet zuletzt gemeldet hat. */
|
/** Kippschalter mit dem Stand, den das Geraet zuletzt gemeldet hat. */
|
||||||
function kippSchalter($d, $schalter, $an)
|
function kippSchalter($d, $schalter, $an)
|
||||||
{
|
{
|
||||||
@@ -291,28 +434,32 @@ function zeichneBeschattung($d)
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
$html = karteAuf($d, $status);
|
$html = karteAuf($d, $status);
|
||||||
|
$html .= "<div class='raum-jalousie'>";
|
||||||
|
|
||||||
|
// Auf, Stop, Zu untereinander: so zeigen die Knoepfe in die Richtung, in
|
||||||
|
// die sie fahren.
|
||||||
if ($auf || $stop || $zu) {
|
if ($auf || $stop || $zu) {
|
||||||
$html .= "<div class='d-flex align-items-center gap-2 mb-2'>";
|
$html .= "<div class='btn-group-vertical btn-group-sm raum-fahrt' role='group'>";
|
||||||
$html .= "<div class='btn-group btn-group-sm flex-grow-1' role='group'>";
|
|
||||||
foreach ([[$auf, "bi-chevron-up", "Auf"], [$stop, "bi-stop-fill", "Stop"],
|
foreach ([[$auf, "bi-chevron-up", "Auf"], [$stop, "bi-stop-fill", "Stop"],
|
||||||
[$zu, "bi-chevron-down", "Zu"]] as $k) {
|
[$zu, "bi-chevron-down", "Zu"]] as $k) {
|
||||||
if (!$k[0]) {
|
if (!$k[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$html .= "<button type='button' class='btn btn-outline-primary' data-cmd='" . intval($k[0]["id"]) . "'"
|
$html .= "<button type='button' class='btn btn-outline-primary' data-cmd='" . intval($k[0]["id"]) . "'"
|
||||||
. " title='" . htmlspecialchars($k[2], ENT_QUOTES) . "'>"
|
. " title='" . htmlspecialchars($k[2], ENT_QUOTES) . "'"
|
||||||
. "<i class='bi " . $k[1] . "'></i><span class='d-none d-sm-inline ms-1'>"
|
. " aria-label='" . htmlspecialchars($k[2], ENT_QUOTES) . "'>"
|
||||||
. htmlspecialchars($k[2]) . "</span></button>";
|
. "<i class='bi " . $k[1] . "'></i></button>";
|
||||||
}
|
}
|
||||||
$html .= "</div>" . mehrMenue($rest) . "</div>";
|
$html .= "</div>";
|
||||||
}
|
}
|
||||||
if ($position) {
|
if ($position) {
|
||||||
$html .= reglerZeile("Position", $position, $position["params"][0], $standPos);
|
$html .= positionsRegler($position, $position["params"][0], $standPos);
|
||||||
}
|
}
|
||||||
if ($neigung) {
|
if ($neigung) {
|
||||||
$html .= reglerZeile("Neigung", $neigung, $neigung["params"][0], $standNeigung);
|
$html .= neigungsRegler($neigung, $neigung["params"][0], $standNeigung);
|
||||||
}
|
}
|
||||||
return $html . karteZu();
|
$html .= mehrMenue($rest);
|
||||||
|
return $html . "</div>" . karteZu();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -537,10 +684,3 @@ function zeichneGeraet($d, $form)
|
|||||||
default: return zeichneSonstiges($d);
|
default: return zeichneSonstiges($d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ueberschrift einer Gruppe. */
|
|
||||||
function gruppenTitel($titel, $symbol)
|
|
||||||
{
|
|
||||||
return "<h6 class='raum-gruppe text-body-secondary'>"
|
|
||||||
. "<i class='bi " . $symbol . " me-1'></i>" . htmlspecialchars($titel) . "</h6>";
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user