Aussengelaende als vierte Etage einhaengen

Das Rendering des Grundstuecks tritt an die Stelle des Vektorplans. Es kommt
aus derselben Art Quelle wie die drei Geschossbilder und passt damit besser
zu ihnen, als der Plan es je koennte; der hat seinen Zweck erfuellt, indem
er die Geometrie sortiert hat.

Freigestellt wird mit einer Flutfuellung vom Rand her, nicht mit einem
Farbtausch: Weiss kommt auch im Bild selbst vor - Hauswand,
Grundstuecksmauer -, und nur was vom Rand aus zusammenhaengend erreichbar
ist, ist wirklich Hintergrund. Aufgefuellt statt beschnitten auf 4:3, weil
1024x792 etwas hoeher ist und Wegschneiden das Bild selbst treffen wuerde.

Etagenbilder und Schalter in home.php kommen jetzt aus einer Schleife.
Ausgeschrieben waren die Blenden bei drei Etagen neun Zeilen und bei vier
schon sechzehn, und jede neue Etage haette alle anderen mit angefasst. Die
Schalter ruecken ab der vierten Etage von 100 auf 78 Einheiten zusammen,
sonst faellt der unterste aus der 300 hohen viewBox.

Die Kachelpositionen sind ein Startwert, kein Endstand: Richtung aus dem
Modell gerechnet - Westen liegt links unten, Sueden rechts unten -, Lage
per Auge im Raster. Der erste Wurf hatte die Terrasse an der falschen
Fassade; im Modell liegt sie an der Suedwestecke.

Lange Raumnamen brechen jetzt um. "Terrasse OG" stand einzeilig ueber die
24 Einheiten breite Kachel hinaus - sichtbar wurde das erst hier, weil im
Aussengelaende jeder Raumname aus zwei Woertern besteht.

Nebenbei: xcursor="pointer" am OG-Schalter war ein Tippfehler, der Kreis
hatte als einziger keinen Zeiger. Das tote border-Attribut am OG-Bild ist
mit weggefallen, SVG kennt es nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 22:53:46 +02:00
co-authored by Claude Opus 5
parent 182b5b66b4
commit abdf6880eb
4 changed files with 75 additions and 62 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 871 KiB

+66 -53
View File
@@ -52,59 +52,57 @@
</g> </g>
</defs> </defs>
<g> <g>
<g id="UGimg" <?php if($_GET["floor"] != "UG"){echo "opacity='0'";} ?> > <?php
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s" /*
* Ein Bild je Etage, dazu fuer jede Etage eine Blende.
* Ausgeschrieben waren das bei drei Etagen neun Zeilen
* und bei vier schon sechzehn - und jede neue Etage
* haette alle anderen mit angefasst.
*
* floorsWithPlan() liefert nur Etagen, deren Raeume
* Koordinaten haben. Eine Etage ohne angeklickte
* Kachelpositionen taucht hier also gar nicht erst auf.
*/
$etagen = floorsWithPlan();
?>
<?php /* Von unten nach oben gestapelt, wie bisher: waehrend der Blende
sind zwei Bilder gleichzeitig halb sichtbar, und dann soll das
obere Geschoss obenauf liegen. */ ?>
<?php foreach (array_reverse($etagen) as $etage): ?>
<g id="<?= $etage ?>img" <?php if ($_GET["floor"] != $etage) echo "opacity='0'"; ?> >
<?php foreach ($etagen as $andere): ?>
<animate begin="<?= $andere ?>.click" attributetype="CSS" attributeName="opacity"
to=<?= $andere === $etage ? "1.0" : "0.0" ?> dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s" <?php endforeach; ?>
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> <image href="assets/img/<?= $etage ?>.png" height="100%" width="100%" x=0 y=0 />
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<image href="assets/img/UG.png" height="100%" width="100%" x=0
y=0 />
</g> </g>
<g id="EGimg" <?php if($_GET["floor"] != "EG"){echo "opacity='0'";} ?> > <?php endforeach; ?>
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s" <?php
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> /*
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s" * Der Kreis ist 50 hoch und sitzt 11 unter der Oberkante
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> * seiner Gruppe. Bei drei Etagen bleibt es bei den
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s" * gewohnten 100 Einheiten Abstand; ab der vierten ruecken
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> * sie zusammen, sonst faellt die unterste aus der 300
<image href="assets/img/EG.png" height="100%" width="100%" x=0 * hohen viewBox heraus.
y=0 /> */
$abstand = count($etagen) > 1
</g> ? min(100, (295 - 61) / (count($etagen) - 1))
<g id="OGimg" <?php if($_GET["floor"] != "OG"){echo "opacity='0'";} ?> > : 0;
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s" // Von Hand mittig gerueckt, je nach Breite der Buchstaben.
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> $textX = ["OG" => 62, "EG" => 64, "UG" => 63, "AG" => 62];
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s" ?>
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> <?php foreach ($etagen as $i => $etage): ?>
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s" <g id="<?= $etage ?>" onclick="switchFloor('<?= $etage ?>')" cursor="pointer"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" /> transform="translate(0,<?= round($i * $abstand, 1) ?>), scale(0.50,0.50)">
<image href="assets/img/OG.png" border="1px solid white" height="100%" width="100%" x=0 <animate id="show<?= $etage ?>" begin=click attributetype="CSS" attributeName="opacity"
y=0 /> from=0 to=1 dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1"
</g> keySplines=".1,0,.27,1" fill="freeze"></animate>
<g id="OG" onclick="switchFloor('OG')" xcursor="pointer" transform="translate(0,0), scale(0.50,0.50)">
<animate id="showOG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze">
</animate>
<use href="#floorBtn" stroke="#aa7713" /> <use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(62,90)">OG</text> <text fill="#aa7713" style="font: 3em sans-serif;"
</g> transform="translate(<?= $textX[$etage] ?? 62 ?>,90)"><?= $etage ?></text>
<g id="EG" onclick="switchFloor('EG')" cursor="pointer" transform="translate(0,100), scale(0.50,0.50)">
<animate id="showEG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze"></animate>
<use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(64,90)">EG</text>
</g>
<g id="UG" onclick="switchFloor('UG')" cursor="pointer" transform="translate(0,200), scale(0.50,0.50)">
<animate id="showUG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze"></animate>
<use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(63,90)">UG</text>
</g> </g>
<?php endforeach; ?>
<?php foreach (floorsWithPlan() as $floor): ?> <?php foreach (floorsWithPlan() as $floor): ?>
<g id="<?= $floor ?>_Info" <?php if ($floor != "OG") echo 'opacity="0" '; ?><?php if($_GET["floor"] != $floor){echo "display='none'";} ?> > <g id="<?= $floor ?>_Info" <?php if ($floor != "OG") echo 'opacity="0" '; ?><?php if($_GET["floor"] != $floor){echo "display='none'";} ?> >
<?php foreach (array_map("mitWerten", roomsOnFloor($floor)) as $room): ?> <?php foreach (array_map("mitWerten", roomsOnFloor($floor)) as $room): ?>
@@ -125,10 +123,25 @@
<?php endif; ?> <?php endif; ?>
<text fill="#fff" style="font: 4px sans-serif;"> <text fill="#fff" style="font: 4px sans-serif;">
<?php if (!$room["werte"]): ?> <?php if (!$room["werte"]): ?>
<!-- Kein Messwert: die Kachel traegt ihren Namen und <?php
oeffnet den Raum. Ein leeres Rechteck saehe aus /*
wie ein Fehler. --> * Kein Messwert: die Kachel traegt ihren Namen und oeffnet den Raum.
<tspan x="12" y="11.5" font-size="1.2em" text-anchor="middle"><?= htmlspecialchars($room["mqtt"]) ?></tspan> * Ein leeres Rechteck saehe aus wie ein Fehler.
*
* Lange Namen brechen am letzten Leerzeichen um. Die Kachel ist 24
* Einheiten breit, und "Terrasse OG" stand einzeilig links und rechts
* darueber hinaus. Aufgefallen ist das erst mit dem Aussengelaende:
* dort besteht jeder Raumname aus zwei Woertern.
*/
$luecke = strrpos($room["mqtt"], " ");
$teile = (strlen($room["mqtt"]) > 8 && $luecke !== false)
? [substr($room["mqtt"], 0, $luecke), substr($room["mqtt"], $luecke + 1)]
: [$room["mqtt"]];
$namenszeilen = count($teile) === 2 ? [9, 15.5] : [11.5];
?>
<?php foreach ($teile as $i => $teil): ?>
<tspan x="12" y="<?= $namenszeilen[$i] ?>" font-size="1.2em" text-anchor="middle"><?= htmlspecialchars($teil) ?></tspan>
<?php endforeach; ?>
<?php endif; ?> <?php endif; ?>
<?php foreach ($room["werte"] as $i => $wert): ?> <?php foreach ($room["werte"] as $i => $wert): ?>
<!-- Der Platzhalter ist nur ein Strich: bevor der <!-- Der Platzhalter ist nur ein Strich: bevor der
+9 -9
View File
@@ -95,20 +95,20 @@ $rooms = [
// Zwei Carports, einer je Wohnpartei - deshalb dieselben Kuerzel wie die // Zwei Carports, einer je Wohnpartei - deshalb dieselben Kuerzel wie die
// Etagen. Die Wattpilot der EG-Partei steht dagegen in der Garage, siehe // Etagen. Die Wattpilot der EG-Partei steht dagegen in der Garage, siehe
// restricted/config.php; am Carport OG haengt der go-e Charger. // restricted/config.php; am Carport OG haengt der go-e Charger.
["floor" => "AG", "mqtt" => "Carport EG", "id" => "carport_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Carport EG", "id" => "carport_eg", "x" => 156, "y" => 214, "werte" => []],
["floor" => "AG", "mqtt" => "Carport OG", "id" => "carport_og", "werte" => []], ["floor" => "AG", "mqtt" => "Carport OG", "id" => "carport_og", "x" => 38, "y" => 155, "werte" => []],
// Veranda und Terrasse gibt es zweimal, je Wohnpartei eine. In der // Veranda und Terrasse gibt es zweimal, je Wohnpartei eine. In der
// Draufsicht laege das obere Paar genau auf dem unteren - deshalb die // Draufsicht laege das obere Paar genau auf dem unteren - deshalb die
// Schraegsicht, siehe restricted/aussenplan.php. // Schraegsicht, siehe restricted/aussenplan.php.
["floor" => "AG", "mqtt" => "Veranda EG", "id" => "veranda_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Veranda EG", "id" => "veranda_eg", "x" => 156, "y" => 132, "werte" => []],
["floor" => "AG", "mqtt" => "Veranda OG", "id" => "veranda_og", "werte" => []], ["floor" => "AG", "mqtt" => "Veranda OG", "id" => "veranda_og", "x" => 150, "y" => 92, "werte" => []],
["floor" => "AG", "mqtt" => "Terrasse EG", "id" => "terrasse_eg", "werte" => []], ["floor" => "AG", "mqtt" => "Terrasse EG", "id" => "terrasse_eg", "x" => 212, "y" => 160, "werte" => []],
["floor" => "AG", "mqtt" => "Terrasse OG", "id" => "terrasse_og", "werte" => []], ["floor" => "AG", "mqtt" => "Terrasse OG", "id" => "terrasse_og", "x" => 205, "y" => 122, "werte" => []],
["floor" => "AG", "mqtt" => "Pergola", "id" => "pergola", "werte" => []], ["floor" => "AG", "mqtt" => "Pergola", "id" => "pergola", "x" => 339, "y" => 108, "werte" => []],
["floor" => "AG", "mqtt" => "Garage", "id" => "garage", "werte" => []], ["floor" => "AG", "mqtt" => "Garage", "id" => "garage", "x" => 103, "y" => 134, "werte" => []],
// Der Garten ist kein Bauteil wie die anderen, aber ein Ort: hier haengen // Der Garten ist kein Bauteil wie die anderen, aber ein Ort: hier haengen
// der Regensensor und die beiden Ventilsteuerungen. // der Regensensor und die beiden Ventilsteuerungen.
["floor" => "AG", "mqtt" => "Garten", "id" => "garten", "werte" => []], ["floor" => "AG", "mqtt" => "Garten", "id" => "garten", "x" => 288, "y" => 180, "werte" => []],
]; ];
/** /**