Cockpit: Schalter filtert wirklich, Balken 18 statt 26 Punkte
Der Schalter „nur aktive“ änderte kaum etwas: Neben ihm filterte noch das Σ-Kennzeichen, und stillgelegte Konten tragen es meist nicht – von 17 inaktiven Konten kam beim Ausschalten genau eines dazu. Das Kennzeichen filtert hier nicht mehr mit, der Schalter ist das einzige Kriterium. Balken jetzt 18 Bildpunkte breit mit 3 Punkten Abstand. Damit das auf dem Schirm ankommt, trägt das SVG seine Maße als Attribute und wird nicht mehr auf die Kachel gestreckt. Die Legende steht neben der Zeichnung, die sonst die halbe Kachel leer ließe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7932830def
commit
0285b760fc
6 changed files with 85 additions and 44 deletions
10
Changes.md
10
Changes.md
|
|
@ -5,11 +5,13 @@
|
|||
- Die Kachel *Vermögensentwicklung* war ein Platzhalter und zeigt jetzt die Kontostände
|
||||
der letzten zwölf Monate je Monatsende – ein Balken pro Monat, ein Farbton pro Konto
|
||||
(`Vermoegensentwicklung::reihe()`, `src/Views/cockpit/vermoegensdiagramm.php`).
|
||||
- Gezählt wird, was auch in der Kontenübersicht in die Summe zählt: Konten mit
|
||||
Σ-Kennzeichen. Negative Stände stapeln unter der Nulllinie.
|
||||
- Negative Stände stapeln unter der Nulllinie.
|
||||
- Schalter *nur aktive* oben rechts an der Kachel, im Standard eingeschaltet: Er blendet
|
||||
stillgelegte Konten aus und merkt sich seinen Zustand über die Einstellungen
|
||||
(`cockpit_vermoegen_nur_aktive`) – auch über das Abmelden hinaus.
|
||||
stillgelegte Konten samt Legendeneintrag aus und merkt sich seinen Zustand über die
|
||||
Einstellungen (`cockpit_vermoegen_nur_aktive`) – auch über das Abmelden hinaus. Er ist
|
||||
das einzige Kriterium; das Σ-Kennzeichen filtert hier **nicht** mit, weil stillgelegte
|
||||
Konten es meist nicht tragen und beim Ausschalten sonst genau das fehlte, was man sehen
|
||||
will.
|
||||
- `Buchung::bewegungenJeKontoUndMonat()` liefert die Monatsbewegungen in einer Abfrage je
|
||||
Quelle – zwölf Stichtagsabfragen wären es sonst.
|
||||
- Mehr Konten als Farbtöne: Die größten behalten ihre Farbe, der Rest wird zu *Übrige
|
||||
|
|
|
|||
|
|
@ -10,9 +10,13 @@ Monate – ein Balken je Monat, ein Farbton je Konto.
|
|||
|
||||
### Woher die Zahlen kommen
|
||||
|
||||
`Vermoegensentwicklung::reihe()` zählt dieselben Konten wie die Summe der Kontenübersicht:
|
||||
die mit gesetztem Σ-Kennzeichen (`in_summe`). Der Stand eines Monats ist der Stand des
|
||||
Vormonats plus dessen Bewegungen:
|
||||
Welche Konten zählen, entscheidet allein der Schalter „nur aktive“. Das Σ-Kennzeichen
|
||||
(`in_summe`) spielt hier **keine** Rolle – anders als in der Kontenübersicht. Stillgelegte
|
||||
Konten tragen es meist nicht; würde es mitfiltern, fiele beim Ausschalten des Schalters
|
||||
genau das weg, was man sehen will. Die Summe der Kachel kann bei ausgeschaltetem Schalter
|
||||
deshalb von der Summe der Kontenübersicht abweichen.
|
||||
|
||||
Der Stand eines Monats ist der Stand des Vormonats plus dessen Bewegungen:
|
||||
|
||||
* `Buchung::saldenJeKonto()` liefert den Stand am Tag vor dem Zeitraum – alles Ältere
|
||||
steckt damit im ersten Balken.
|
||||
|
|
@ -63,11 +67,17 @@ Die Achse rundet über `Vermoegensentwicklung::skala()` auf Schritte von 1, 2, 2
|
|||
mal einer Zehnerpotenz und schließt die Null immer ein. Jedes Balkenstück trägt ein
|
||||
`<title>` mit Konto, Monat und Betrag – das ist der Tooltip, ohne eine Zeile JavaScript.
|
||||
|
||||
Die Legende führt nur Farbe und Kontoname. Die Beträge stehen am Balken im Tooltip und in
|
||||
Die Maße stehen in echten Bildpunkten: Ein Balken ist 18 Punkte breit, zwischen zwei
|
||||
Monaten bleiben 3. Damit das auch auf dem Schirm so ankommt, trägt das `<svg>` Breite und
|
||||
Höhe als Attribute und wird **nicht** auf die Kachel gestreckt; `max-width: 100%` lässt es
|
||||
erst mitschrumpfen, wenn die Kachel schmaler wird als die Zeichnung.
|
||||
|
||||
Die Legende führt nur Farbe und Kontoname und steht neben der Zeichnung – die schmale
|
||||
Zeichnung ließe sonst die halbe Kachel leer. Die Beträge stehen am Balken im Tooltip und in
|
||||
der Kachel *Kontostände*; in der Legende kosteten sie nur Breite. Die Kachel greift über
|
||||
zwei Spalten des Cockpit-Rasters (`.kachelraster.dicht`) – schmal genug, um die übrigen
|
||||
Kacheln danebenstehen zu lassen, breit genug für zwölf Balken. Unterhalb von 820 px fällt
|
||||
der Ausgriff weg, sonst erzwänge er im einspaltigen Raster einen waagerechten Rollbalken.
|
||||
zwei Spalten des Cockpit-Rasters (`.kachelraster.dicht`). Unterhalb von 820 px fällt der
|
||||
Ausgriff weg, sonst erzwänge er im einspaltigen Raster einen waagerechten Rollbalken; dort
|
||||
rutscht auch die Legende unter die Zeichnung.
|
||||
|
||||
## Tests
|
||||
|
||||
|
|
|
|||
|
|
@ -371,11 +371,22 @@ form.inline { display: inline; margin: 0; }
|
|||
.serie-11 { --farbe: #e07b91; }
|
||||
.serie-12 { --farbe: #7b8a99; }
|
||||
|
||||
/* Das SVG bringt seine Maße als Attribute mit und wird nicht auf die Kachel
|
||||
gestreckt: Nur so sind die 18 Punkte Balkenbreite auch 18 Bildpunkte. Erst
|
||||
wenn die Kachel schmaler wird als die Zeichnung, skaliert sie mit. */
|
||||
.diagrammbereich {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
gap: .5rem 1.5rem;
|
||||
}
|
||||
|
||||
.diagramm {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
overflow: visible;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.diagramm rect { fill: var(--farbe); }
|
||||
|
|
@ -390,27 +401,34 @@ form.inline { display: inline; margin: 0; }
|
|||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
/* Die Schrift skaliert mit dem viewBox: In der schmalen Kachel schrumpft sie um
|
||||
ein Viertel, deshalb hier größer als im Fließtext angesetzt. */
|
||||
.diagramm-achse,
|
||||
.diagramm-beschriftung {
|
||||
fill: var(--text-gedaempft);
|
||||
font-family: var(--schrift);
|
||||
font-size: 14px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.diagramm-achse { font-family: var(--schrift-zahl); }
|
||||
/* Ziffernschrift für die Achse, aber schmal genug für 21 Punkte Spaltenabstand
|
||||
bleiben die Monatskürzel darunter. */
|
||||
.diagramm-achse {
|
||||
font-family: var(--schrift-zahl);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.diagramm-beschriftung.schwach { opacity: .7; }
|
||||
|
||||
/* Neben der Zeichnung statt darunter: Die schmale Zeichnung ließe sonst die
|
||||
halbe Kachel leer. */
|
||||
.diagrammlegende {
|
||||
list-style: none;
|
||||
margin: .9rem 0 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
flex: 1 1 11rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
|
||||
gap: .1rem 1.2rem;
|
||||
font-size: .88rem;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.diagrammlegende li {
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ use Finanzmanager\Models\Konto;
|
|||
* Die Kontostände der letzten zwölf Monate, je Konto und Monatsende – Grundlage
|
||||
* der Cockpit-Kachel *Vermögensentwicklung*.
|
||||
*
|
||||
* Gezählt wird, was auch in der Kontenübersicht in die Summe zählt: Konten mit
|
||||
* gesetztem Kennzeichen `in_summe`. Der Schalter „nur aktive“ an der Kachel
|
||||
* entscheidet, ob stillgelegte Konten dazugehören: ausgeschaltet zeigt er auch
|
||||
* das Vermögen, das damals auf inzwischen aufgelösten Konten lag.
|
||||
* Einziges Kriterium ist der Schalter „nur aktive“ an der Kachel: eingeschaltet
|
||||
* zählen die geführten Konten, ausgeschaltet alle. Das Σ-Kennzeichen (`in_summe`)
|
||||
* bleibt hier ausdrücklich außen vor – stillgelegte Konten tragen es meist nicht,
|
||||
* und dann fiele beim Ausschalten genau das weg, was man sehen will.
|
||||
*/
|
||||
class Vermoegensentwicklung
|
||||
{
|
||||
|
|
@ -54,10 +54,6 @@ class Vermoegensentwicklung
|
|||
$summen = array_fill(0, count($monate), 0.0);
|
||||
|
||||
foreach (Konto::alle($nurAktive) as $konto) {
|
||||
if ((int)$konto['in_summe'] !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = (int)$konto['id'];
|
||||
$stand = (float)$konto['anfangssaldo'] + ($anfang[$id] ?? 0.0);
|
||||
$werte = [];
|
||||
|
|
|
|||
|
|
@ -44,17 +44,22 @@ foreach ($monate as $nummer => $monat) {
|
|||
|
||||
$skala = Vermoegensentwicklung::skala($grenzwerte);
|
||||
|
||||
$breite = 760;
|
||||
$hoehe = 250;
|
||||
$links = 82;
|
||||
$rechts = 10;
|
||||
$oben = 12;
|
||||
$unten = 40;
|
||||
// Maße in echten Bildpunkten: Das SVG trägt Breite und Höhe als Attribute und
|
||||
// wird deshalb nicht auf die Kachel gestreckt. Ein Balken ist 18 Punkte breit,
|
||||
// zwischen zwei Monaten bleiben 3 – erst unterhalb der eigenen Breite skaliert
|
||||
// die Zeichnung mit (max-width in app.css).
|
||||
$balken = 18;
|
||||
$luecke = 3;
|
||||
$links = 52;
|
||||
$rechts = 6;
|
||||
$oben = 10;
|
||||
$unten = 32;
|
||||
|
||||
$plotB = $breite - $links - $rechts;
|
||||
$plotH = $hoehe - $oben - $unten;
|
||||
$spalte = $plotB / max(1, $anzahl);
|
||||
$balken = min(40.0, $spalte * 0.62);
|
||||
$spalte = $balken + $luecke;
|
||||
$plotB = $spalte * $anzahl;
|
||||
$plotH = 150;
|
||||
$breite = $links + $plotB + $rechts;
|
||||
$hoehe = $oben + $plotH + $unten;
|
||||
|
||||
$y = static function (float $wert) use ($skala, $oben, $plotH): float {
|
||||
return round($oben + $plotH * ($skala['max'] - $wert) / ($skala['max'] - $skala['min']), 2);
|
||||
|
|
@ -76,7 +81,9 @@ $zeitraum = $monate[0]['kuerzel'] . ' ' . $monate[0]['jahrKurz']
|
|||
. ' bis ' . $monate[$anzahl - 1]['kuerzel'] . ' ' . $monate[$anzahl - 1]['jahrKurz'];
|
||||
?>
|
||||
|
||||
<svg class="diagramm" viewBox="0 0 <?= $breite ?> <?= $hoehe ?>" role="img"
|
||||
<div class="diagrammbereich">
|
||||
<svg class="diagramm" width="<?= $breite ?>" height="<?= $hoehe ?>"
|
||||
viewBox="0 0 <?= $breite ?> <?= $hoehe ?>" role="img"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
aria-label="Kontostände je Monatsende, <?= View::h($zeitraum) ?>">
|
||||
<title>Vermögensentwicklung <?= View::h($zeitraum) ?></title>
|
||||
|
|
@ -121,10 +128,10 @@ $zeitraum = $monate[0]['kuerzel'] . ' ' . $monate[0]['jahrKurz']
|
|||
</rect>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<text class="diagramm-beschriftung" x="<?= $mitte($nummer) ?>" y="<?= $hoehe - 22 ?>"
|
||||
<text class="diagramm-beschriftung" x="<?= $mitte($nummer) ?>" y="<?= $hoehe - 18 ?>"
|
||||
text-anchor="middle"><?= View::h($monat['kuerzel']) ?></text>
|
||||
<?php if ($monat['monat'] === 1 || $nummer === 0): ?>
|
||||
<text class="diagramm-beschriftung schwach" x="<?= $mitte($nummer) ?>" y="<?= $hoehe - 6 ?>"
|
||||
<text class="diagramm-beschriftung schwach" x="<?= $mitte($nummer) ?>" y="<?= $hoehe - 5 ?>"
|
||||
text-anchor="middle"><?= View::h($monat['jahrKurz']) ?></text>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
|
|
@ -140,3 +147,4 @@ $zeitraum = $monate[0]['kuerzel'] . ' ' . $monate[0]['jahrKurz']
|
|||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class VermoegensentwicklungTest extends TestCase
|
|||
$this->zwoelfMonateBisHeute();
|
||||
$this->staendeWachsenMonatFuerMonat();
|
||||
$this->umbuchungVerschiebtZwischenKonten();
|
||||
$this->ohneSummenkennzeichenKeinBalken();
|
||||
$this->summenkennzeichenFiltertNicht();
|
||||
$this->schalterFiltertStillgelegteKonten();
|
||||
$this->mehrKontenAlsFarbenWerdenZusammengefasst();
|
||||
$this->skalaRundetAufLesbareSchritte();
|
||||
|
|
@ -119,8 +119,10 @@ class VermoegensentwicklungTest extends TestCase
|
|||
// Die Kreditkarte steht im Minus – sie zieht die Summe herunter.
|
||||
$karte = $this->konto($reihe, $this->kreditkarte);
|
||||
$this->assertEquals(-200.0, $karte['werte'][11], 'Negativer Stand bleibt negativ');
|
||||
$this->assertEquals(1600.0, $reihe['summen'][11], 'Summe ist Giro minus Kreditkarte');
|
||||
$this->assert($reihe['hatWerte'], 'Es gibt etwas zu zeichnen');
|
||||
|
||||
// Giro 1800, Kreditkarte -200, Auslagen 5000, Sparbuch 0.
|
||||
$this->assertEquals(6600.0, $reihe['summen'][11], 'Die Summe ist der Stapel aller Konten');
|
||||
}
|
||||
|
||||
private function umbuchungVerschiebtZwischenKonten(): void
|
||||
|
|
@ -144,13 +146,18 @@ class VermoegensentwicklungTest extends TestCase
|
|||
);
|
||||
}
|
||||
|
||||
private function ohneSummenkennzeichenKeinBalken(): void
|
||||
/**
|
||||
* Das Σ-Kennzeichen entscheidet hier nichts: Stillgelegte Konten tragen es
|
||||
* meist nicht, und dann fiele beim Ausschalten des Schalters genau das weg,
|
||||
* was man sehen will.
|
||||
*/
|
||||
private function summenkennzeichenFiltertNicht(): void
|
||||
{
|
||||
$reihe = $this->reihe();
|
||||
|
||||
$this->assertNull(
|
||||
$this->assertNotEmpty(
|
||||
$this->konto($reihe, $this->auslagen),
|
||||
'Ein Konto ohne Σ-Kennzeichen zeichnet keinen Balken'
|
||||
'Ein aktives Konto ohne Σ-Kennzeichen zeichnet trotzdem einen Balken'
|
||||
);
|
||||
|
||||
// Ein Konto, das im ganzen Zeitraum auf null steht, bläht nur die Legende auf.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue