Solar: neue Energiefluss-Uebersicht, anpassbar je Haus
Das feste realtime.svg ist ersetzt durch einen Katalog (js/solar/energieflussKatalog.js: jeder Kreis einmal, samt Werten aus MQTT) und einen Renderer (js/solar/energiefluss.js): Ringe mit Segmenten, Fluesse als Boegen mit laufenden Punkten, Fuellstandswelle fuer Batterie und Auto, animierte Symbole, Plaketten, Hochkant-Ansicht auf schmalen Schirmen. Hierarchie und Lage wie bisher: Quellen -> Wechselrichter -> Verbrauch -> OG/EG/UG -> Wallboxen, Heizstab. Einstellungen -> Uebersicht: Kreise ein/aus (Kinder ruecken eine Ebene hoeher), Namen, Lage per Ziehen in der Vorschau, PV-Flaechen. Gespeichert werden nur Abweichungen in homeMesh.energiefluss. Der PV-Lageplan hinter der Sonne liegt unveraendert als assets/img/pvplan.svg und ist ueber den Umschalter Uebersicht/Anlage erreichbar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+170
@@ -3431,3 +3431,173 @@ input[type='range']::-webkit-slider-runnable-track {
|
||||
border-color: #00788F;
|
||||
color: var(--ton-schrift, #e8ede9);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Energiefluss-Übersicht (js/solar/energiefluss.js, Katalog in
|
||||
js/solar/energieflussKatalog.js).
|
||||
|
||||
Farben je Kreis kommen als --farbe aus dem Katalog, Breite und Tempo der
|
||||
Flüsse als --breite/--dauer aus dem Renderer. Alles Übrige steht hier.
|
||||
Transformationen liegen nie auf Elementen mit transform-Attribut (Kreis-
|
||||
gruppe, Plakette) - CSS würde deren Lage überschreiben.
|
||||
========================================================================== */
|
||||
.enf-behaelter { position: relative; }
|
||||
svg.enf {
|
||||
display: block; width: 100%; height: auto; max-height: 80vh;
|
||||
font-family: "Poppins", system-ui, sans-serif;
|
||||
user-select: none; -webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
svg.enf.enf-hoch { max-height: none; }
|
||||
|
||||
/* --- Kreis ------------------------------------------------------------- */
|
||||
.enf .enf-hof { fill: #1c2024; stroke: rgba(255, 255, 255, .06); stroke-width: 1.5; transition: stroke .3s, stroke-width .3s; }
|
||||
.enf .enf-spur { fill: none; stroke: #2b3139; stroke-width: 14; }
|
||||
.enf .enf-bogen {
|
||||
fill: none; stroke-width: 14; stroke-dasharray: 0 100;
|
||||
transition: stroke-dasharray 1s cubic-bezier(.2, .7, .2, 1), stroke-dashoffset 1s cubic-bezier(.2, .7, .2, 1), stroke .4s;
|
||||
}
|
||||
.enf .enf-scheibe { fill: #20252b; }
|
||||
.enf .enf-wert { fill: var(--ton-schrift, #e8ede9); font-size: 32px; font-weight: 600; text-anchor: middle; font-variant-numeric: tabular-nums; }
|
||||
.enf .enf-neben { fill: var(--ton-schrift-2, #9aa6ad); font-size: 14.5px; text-anchor: middle; font-variant-numeric: tabular-nums; }
|
||||
.enf .enf-name {
|
||||
fill: var(--ton-schrift-2, #9aa6ad); font-size: 16px; font-weight: 600; text-anchor: middle; letter-spacing: .08em; text-transform: uppercase;
|
||||
/* Kontur in Kartenfarbe: bleibt lesbar, wo ein Fluss unter dem Namen durchlaeuft. */
|
||||
paint-order: stroke; stroke: var(--ton-flaeche, #23282c); stroke-width: 7px; stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.enf .enf-koerper { transform-box: view-box; transform-origin: 0 0; transition: transform .3s cubic-bezier(.2, .7, .2, 1), opacity .6s; }
|
||||
.enf .enf-ruhe .enf-koerper { opacity: .6; }
|
||||
.enf .enf-ruhe .enf-name { opacity: .7; }
|
||||
.enf .enf-aus { opacity: .3; }
|
||||
.enf .enf-aus .enf-spur { stroke-dasharray: 8 8; }
|
||||
|
||||
.enf .enf-klickbar { cursor: pointer; outline: none; }
|
||||
.enf .enf-klickbar:hover .enf-koerper { transform: scale(1.045); }
|
||||
.enf .enf-klickbar:hover .enf-hof,
|
||||
.enf .enf-klickbar:focus-visible .enf-hof { stroke: var(--farbe); stroke-width: 3; }
|
||||
.enf .enf-tipp circle { fill: #262c33; stroke: #3a424b; stroke-width: 1.5; }
|
||||
.enf .enf-tipp path { fill: none; stroke: var(--farbe); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; transition: transform .25s; }
|
||||
.enf .enf-klickbar:hover .enf-tipp path { transform: translateX(2px); }
|
||||
|
||||
/* --- Füllstand als Welle ------------------------------------------------ */
|
||||
.enf .enf-fuellung {
|
||||
--r: 67;
|
||||
transform: translateY(calc(var(--r) * (1 - 2 * var(--stand)) * 1px));
|
||||
transition: transform 1.4s cubic-bezier(.2, .7, .2, 1);
|
||||
}
|
||||
.enf .enf-welle { fill: var(--farbe); fill-opacity: .14; animation: enf-wogen 8s linear infinite; }
|
||||
@keyframes enf-wogen { to { transform: translateX(calc(var(--r) * 2px)); } }
|
||||
|
||||
/* --- Symbole ------------------------------------------------------------ */
|
||||
.enf .enf-symbol { color: var(--farbe); fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.enf .enf-s-fein { stroke-width: 1.1; opacity: .75; }
|
||||
.enf .enf-s-kern { fill: currentColor; fill-opacity: .2; transition: fill-opacity .6s; }
|
||||
.enf .enf-an .enf-s-kern { fill-opacity: .55; }
|
||||
.enf .enf-s-strahlen { transform-box: view-box; transform-origin: 0 0; opacity: .55; transition: opacity .6s; }
|
||||
.enf .enf-an .enf-s-strahlen { opacity: 1; animation: enf-drehen 30s linear infinite; }
|
||||
@keyframes enf-drehen { to { transform: rotate(360deg); } }
|
||||
|
||||
.enf .enf-s-stand {
|
||||
fill: currentColor; stroke: none; opacity: .45;
|
||||
transform-box: fill-box; transform-origin: 50% 100%;
|
||||
transform: scaleY(var(--stand, 0)); transition: transform 1.2s cubic-bezier(.2, .7, .2, 1);
|
||||
}
|
||||
.enf .enf-s-blitz { fill: currentColor; stroke: none; opacity: 0; transition: opacity .4s; }
|
||||
.enf .enf-sym-akku .enf-s-blitz { fill: #fff; }
|
||||
.enf .enf-s-blitz.enf-s-an,
|
||||
.enf .enf-laden .enf-s-blitz,
|
||||
.enf .enf-an.enf-knoten .enf-sym-wallbox .enf-s-blitz { opacity: 1; }
|
||||
.enf .enf-laden .enf-s-blitz,
|
||||
.enf .enf-an .enf-sym-wallbox .enf-s-blitz { animation: enf-puls 1.8s ease-in-out infinite; }
|
||||
@keyframes enf-puls { 50% { opacity: .35; } }
|
||||
|
||||
.enf .enf-an .enf-s-welle { animation: enf-puls 1.4s ease-in-out infinite; }
|
||||
.enf .enf-s-ebene { fill: currentColor; stroke: none; opacity: .38; }
|
||||
.enf .enf-an .enf-sym-wallbox .enf-s-kabel { stroke-dasharray: 2.4 2.4; animation: enf-kabel .9s linear infinite; }
|
||||
@keyframes enf-kabel { to { stroke-dashoffset: -4.8; } }
|
||||
.enf .enf-s-temps rect { stroke: none; fill: #2b3139; opacity: .9; transition: fill 1.5s; }
|
||||
.enf .enf-s-spirale { stroke-width: 1.3; transition: stroke .4s; }
|
||||
.enf .enf-an .enf-s-spirale { stroke: #ffb04a; animation: enf-gluehen 1.1s ease-in-out infinite alternate; }
|
||||
@keyframes enf-gluehen { to { stroke: #ff5a2a; } }
|
||||
|
||||
/* --- Plaketten ---------------------------------------------------------- */
|
||||
.enf .enf-plakette { animation: enf-einblenden .5s both; animation-delay: calc(var(--i) * 80ms); }
|
||||
.enf .enf-plakette circle,
|
||||
.enf .enf-plakette rect { fill: #1c2024; stroke: var(--pfarbe); stroke-width: 2; }
|
||||
.enf .enf-plakette-glyph { font-family: bootstrap-icons; font-size: 16px; fill: var(--pfarbe); text-anchor: middle; dominant-baseline: central; }
|
||||
.enf .enf-plakette-text { font-size: 14px; font-weight: 600; fill: var(--ton-schrift, #e8ede9); dominant-baseline: central; }
|
||||
|
||||
/* --- Bewässerung --------------------------------------------------------- */
|
||||
.enf .enf-zone-glyph { font-family: bootstrap-icons; font-size: 17px; fill: currentColor; color: #6c757d; text-anchor: middle; dominant-baseline: central; transition: color .4s; }
|
||||
.enf .enf-zone-name { font-size: 15px; fill: var(--ton-schrift-2, #9aa6ad); dominant-baseline: central; }
|
||||
.enf .enf-zone-status { font-size: 15px; font-weight: 600; fill: var(--ton-schrift, #e8ede9); text-anchor: end; dominant-baseline: central; font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* --- Flüsse -------------------------------------------------------------- */
|
||||
.enf .enf-bett {
|
||||
fill: none; stroke: #252b31; stroke-linecap: round;
|
||||
stroke-width: calc(var(--breite, 0) * 1px + 5px);
|
||||
stroke-dasharray: 1 1; stroke-dashoffset: 1;
|
||||
transition: stroke-width .8s;
|
||||
animation: enf-zeichnen .9s cubic-bezier(.5, 0, .2, 1) forwards; animation-delay: var(--verz);
|
||||
}
|
||||
@keyframes enf-zeichnen { to { stroke-dashoffset: 0; } }
|
||||
.enf .enf-strom,
|
||||
.enf .enf-strom-hof {
|
||||
fill: none; stroke: var(--farbe); stroke-linecap: round;
|
||||
stroke-dasharray: 0 20;
|
||||
/* Stufen statt stetig: stroke-dashoffset laeuft nicht auf dem Compositor,
|
||||
jede Stufe ist ein Neuzeichnen. 20 je Abschnitt sehen fluessig aus. */
|
||||
animation: enf-fliessen var(--dauer, 1.5s) steps(20) infinite;
|
||||
transition: stroke-width .8s, opacity .6s;
|
||||
}
|
||||
.enf .enf-strom { stroke-width: calc(var(--breite, 0) * 1px); }
|
||||
.enf .enf-strom-hof { stroke-width: calc(var(--breite, 0) * 1.9px); opacity: .14; }
|
||||
.enf .enf-rueck .enf-strom,
|
||||
.enf .enf-rueck .enf-strom-hof { animation-direction: reverse; }
|
||||
.enf .enf-still .enf-strom,
|
||||
.enf .enf-still .enf-strom-hof { opacity: 0; animation: none; }
|
||||
@keyframes enf-fliessen { to { stroke-dashoffset: -20; } }
|
||||
|
||||
/* --- Auftritt ------------------------------------------------------------ */
|
||||
.enf .enf-koerper { animation: enf-erscheinen .7s cubic-bezier(.2, .9, .3, 1.25) backwards; animation-delay: var(--verz); }
|
||||
.enf .enf-name { animation: enf-einblenden .7s backwards; animation-delay: calc(var(--verz) + 150ms); }
|
||||
@keyframes enf-erscheinen { from { opacity: 0; transform: scale(.55); } }
|
||||
@keyframes enf-einblenden { from { opacity: 0; } }
|
||||
|
||||
.enf.enf-pause,
|
||||
.enf.enf-pause * { animation-play-state: paused !important; }
|
||||
|
||||
/* --- Bearbeiten (Einstellungen) ------------------------------------------ */
|
||||
.enf.enf-bearbeiten .enf-koerper,
|
||||
.enf.enf-bearbeiten .enf-name,
|
||||
.enf.enf-bearbeiten .enf-bett { animation: none; stroke-dashoffset: 0; }
|
||||
.enf.enf-bearbeiten .enf-ziehbar { cursor: grab; touch-action: none; }
|
||||
.enf.enf-bearbeiten .enf-zieht { cursor: grabbing; }
|
||||
.enf.enf-bearbeiten .enf-zieht .enf-hof { stroke: var(--farbe); stroke-width: 3; }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.enf, .enf * { animation: none !important; transition: none !important; }
|
||||
.enf .enf-bett { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
/* --- Einstellungen: Reiter "Übersicht" ------------------------------------ */
|
||||
.enf-vorschau { background: var(--ton-grund, #191d20); border-radius: var(--ton-radius, .875rem); padding: .5rem; position: sticky; top: 4.5rem; }
|
||||
.enf-e-zeile {
|
||||
display: grid; grid-template-columns: auto minmax(0, 1fr) auto 1.2rem; gap: .35rem .7rem; align-items: center;
|
||||
padding: .45rem 0; border-bottom: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
||||
}
|
||||
.enf-e-zeile.enf-e-aus .enf-e-name { opacity: .5; }
|
||||
.enf-e-name { display: flex; align-items: center; gap: .55rem; margin: 0; }
|
||||
.enf-e-punkt { flex: 0 0 auto; width: .7rem; height: .7rem; border-radius: 50%; background: var(--farbe); box-shadow: 0 0 0 3px color-mix(in srgb, var(--farbe) 22%, transparent); }
|
||||
.enf-e-eltern { white-space: nowrap; }
|
||||
.enf-e-flaechen { grid-column: 2 / -1; padding: .2rem 0 .3rem; }
|
||||
.enf-e-flaeche { display: grid; grid-template-columns: 2.2rem minmax(0, 1fr) 4.2rem 4.2rem 1.2rem; gap: .35rem; align-items: center; margin-bottom: .3rem; }
|
||||
.enf-e-flaeche .form-control.form-control-color { width: 2.2rem; height: 1.9rem; padding: .15rem; }
|
||||
|
||||
/* --- Karte: Umschalter Übersicht / Anlage -------------------------------- */
|
||||
.enf-umschalter { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--ton-radius-klein, .5rem); background: var(--ton-grund, #191d20); }
|
||||
.enf-umschalter .btn.btn-sm { border: 0; color: var(--ton-schrift-2, #9aa6ad); font-weight: 600; padding: .2rem .8rem; }
|
||||
.enf-umschalter .btn.btn-sm.active { background: var(--ton-flaeche-2, #2b3237); color: var(--ton-schrift, #e8ede9); }
|
||||
.enf-ansicht[hidden] { display: none !important; }
|
||||
.enf-ansicht.enf-rein { animation: enf-ansicht-rein .35s cubic-bezier(.2, .7, .2, 1); }
|
||||
@keyframes enf-ansicht-rein { from { opacity: 0; transform: scale(.98); } }
|
||||
|
||||
Reference in New Issue
Block a user