bugfix dashboard #16
@@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
## [Niet vrijgegeven]
|
## [Niet vrijgegeven]
|
||||||
|
|
||||||
|
### Opgelost
|
||||||
|
- Het laatste label op de x-as viel over zijn buurman heen (`mei '26` en `26`
|
||||||
|
over elkaar). De stap werd vanaf het begin van de reeks geteld en het laatste
|
||||||
|
punt werd daar los bovenop geforceerd, zodat het op willekeurige afstand van
|
||||||
|
zijn voorganger landde — bij een reeks die niet toevallig op een veelvoud
|
||||||
|
uitkwam, pal ernaast. De stap telt nu terug vanaf het laatste punt: dat valt
|
||||||
|
daarmee per definitie op een stap en houdt volle tussenruimte, zonder dat er
|
||||||
|
nog een uitzondering voor nodig is
|
||||||
|
- De breedte waarop de grafiek rekent ging van 46 naar 54px per label, zodat er
|
||||||
|
lucht tussen staat in plaats van kop-aan-kop. Over reekslengtes van 13 tot 120
|
||||||
|
punten blijft de tussenruimte nu minimaal 57px
|
||||||
|
|
||||||
|
## [1.0.9] - 2026-09-17
|
||||||
|
|
||||||
### Gewijzigd
|
### Gewijzigd
|
||||||
- De x-as van beide grafieken toont korte maandlabels (`sep '26`) in plaats van
|
- De x-as van beide grafieken toont korte maandlabels (`sep '26`) in plaats van
|
||||||
een volledige datum bij elk punt, en ze staan rechtop in plaats van 45 graden
|
een volledige datum bij elk punt, en ze staan rechtop in plaats van 45 graden
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Eigen vermogen · Schulden · Voortgang · Gebruikersbeheer
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
<img src="docs/screenshot-dashboard.png" alt="VibeFinance dashboard" width="820">
|
<img src="docs/screenshot-dashboard.png" alt="VibeFinance dashboard" width="820">
|
||||||
@@ -181,6 +181,16 @@ inleglijn is per definitie gelijk aan de KPI "Totaal geïnvesteerde fiat" — be
|
|||||||
rekenen het oudste voortgangsmoment als startinleg en tellen daar de stortingen
|
rekenen het oudste voortgangsmoment als startinleg en tellen daar de stortingen
|
||||||
per rij bij op.
|
per rij bij op.
|
||||||
|
|
||||||
|
De x-as noemt maanden (`sep '26`), niet losse datums: de grafiek rekent uit
|
||||||
|
hoeveel labels er naast elkaar passen en toont er zoveel, terugtellend vanaf het
|
||||||
|
laatste punt zodat dat er altijd bij staat. Bij een langere reeks dunt hij
|
||||||
|
vanzelf verder uit. De exacte dag lees je in de tooltip. De vermogenslijn is een
|
||||||
|
Catmull-Rom spline; de inleglijn krijgt bewust rechte segmenten, omdat een
|
||||||
|
spline tussen twee punten iets buiten hun bereik uitschiet en dat bij een reeks
|
||||||
|
die nooit terugloopt een daling zou tekenen die er niet is. Beide lijnen delen
|
||||||
|
de tekenhulp in
|
||||||
|
[`frontend/src/utils/grafiek.js`](frontend/src/utils/grafiek.js).
|
||||||
|
|
||||||
Onder **Instellingen** kies je een van de negen kleurthema's. Thema en
|
Onder **Instellingen** kies je een van de negen kleurthema's. Thema en
|
||||||
licht/donker staan los van elkaar: het thema levert het accent, de schakelaar de
|
licht/donker staan los van elkaar: het thema levert het accent, de schakelaar de
|
||||||
ondergrond. De paletten staan in
|
ondergrond. De paletten staan in
|
||||||
@@ -233,7 +243,8 @@ vibefinance/
|
|||||||
│ ├── main.jsx
|
│ ├── main.jsx
|
||||||
│ ├── version.js # Draaiende versie (__APP_VERSION__ uit de build)
|
│ ├── version.js # Draaiende versie (__APP_VERSION__ uit de build)
|
||||||
│ ├── constants/ # index.js (kleuren, tabs, begindata), themas.js
|
│ ├── constants/ # index.js (kleuren, tabs, begindata), themas.js
|
||||||
│ ├── utils/ # format.js (bedragen/datums), storage.js
|
│ ├── utils/ # format.js (bedragen/datums), storage.js,
|
||||||
|
│ │ # grafiek.js (SVG-padberekening)
|
||||||
│ ├── hooks/ # useTheme, useUpdateCheck, useKolomBreedtes
|
│ ├── hooks/ # useTheme, useUpdateCheck, useKolomBreedtes
|
||||||
│ ├── context/ # AppContext (global state + API sync + backup)
|
│ ├── context/ # AppContext (global state + API sync + backup)
|
||||||
│ ├── components/
|
│ ├── components/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vibefinance-frontend",
|
"name": "vibefinance-frontend",
|
||||||
"version": "1.0.8",
|
"version": "1.0.10-dev",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -179,9 +179,13 @@ function MiniLineChart({ vData, fiatData, darkMode, T }) {
|
|||||||
const mx = Math.max(...vals, ...fVals) * 1.05;
|
const mx = Math.max(...vals, ...fVals) * 1.05;
|
||||||
const rng = mx - mn || 1;
|
const rng = mx - mn || 1;
|
||||||
const iW = W - pl - pr, iH = H - pt - pb;
|
const iW = W - pl - pr, iH = H - pt - pb;
|
||||||
// Eén label "sep '26" is bij deze lettergrootte ongeveer 46px breed. Zoveel
|
// Eén label "sep '26" is bij deze lettergrootte ongeveer 54px breed inclusief
|
||||||
// passen er dus naast elkaar; de rest wordt overgeslagen.
|
// wat lucht ernaast. Zoveel passen er naast elkaar; de rest wordt
|
||||||
const labelStap = Math.max(1, Math.ceil(vData.length / Math.max(1, Math.floor(iW / 46))));
|
// overgeslagen. De stap telt vanaf het láátste punt terug, niet vanaf het
|
||||||
|
// eerste: dat punt is de datum waar je naar kijkt en moet er altijd bij staan.
|
||||||
|
// Forceerden we hem er los bovenop, dan botste hij op willekeurige afstand
|
||||||
|
// tegen zijn voorganger — precies wat er eerst misging.
|
||||||
|
const labelStap = Math.max(1, Math.ceil(vData.length / Math.max(1, Math.floor(iW / 54))));
|
||||||
const xs = vData.map((_, i) => pl + (i / Math.max(vData.length - 1, 1)) * iW);
|
const xs = vData.map((_, i) => pl + (i / Math.max(vData.length - 1, 1)) * iW);
|
||||||
const ys = vals.map((v) => pt + (1 - (v - mn) / rng) * iH);
|
const ys = vals.map((v) => pt + (1 - (v - mn) / rng) * iH);
|
||||||
const fYs = fVals.map((v) => pt + (1 - (v - mn) / rng) * iH);
|
const fYs = fVals.map((v) => pt + (1 - (v - mn) / rng) * iH);
|
||||||
@@ -316,7 +320,9 @@ function MiniLineChart({ vData, fiatData, darkMode, T }) {
|
|||||||
kijkt. De exacte dag lees je in de tooltip. */}
|
kijkt. De exacte dag lees je in de tooltip. */}
|
||||||
{xs.map((x, i) => {
|
{xs.map((x, i) => {
|
||||||
const laatste = i === xs.length - 1;
|
const laatste = i === xs.length - 1;
|
||||||
if (i % labelStap !== 0 && !laatste) return null;
|
// Terugtellen vanaf het eind: het laatste punt valt zo vanzelf op een
|
||||||
|
// stap en houdt volle afstand tot zijn voorganger.
|
||||||
|
if ((xs.length - 1 - i) % labelStap !== 0) return null;
|
||||||
return (
|
return (
|
||||||
<g key={i}>
|
<g key={i}>
|
||||||
<line x1={x} y1={pt + iH} x2={x} y2={pt + iH + 4}
|
<line x1={x} y1={pt + iH} x2={x} y2={pt + iH + 4}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
|||||||
// pb was 62 voor gedraaide datumlabels. Die staan nu rechtop en zijn korter.
|
// pb was 62 voor gedraaide datumlabels. Die staan nu rechtop en zijn korter.
|
||||||
const W = 700, pl = 64, pr = 16, pt2 = 16, pb = 34;
|
const W = 700, pl = 64, pr = 16, pt2 = 16, pb = 34;
|
||||||
const iW = W - pl - pr, iH = H - pt2 - pb;
|
const iW = W - pl - pr, iH = H - pt2 - pb;
|
||||||
// Eén label "sep '26" is ongeveer 46px breed; zoveel passen er naast elkaar.
|
// Eén label "sep '26" is ongeveer 54px breed inclusief lucht ernaast. De stap
|
||||||
const labelStap = Math.max(1, Math.ceil(pts.length / Math.max(1, Math.floor(iW / 46))));
|
// telt vanaf het laatste punt terug, zodat dat er altijd bij staat zonder op
|
||||||
|
// zijn voorganger te botsen. Zie DashboardTab voor de uitleg.
|
||||||
|
const labelStap = Math.max(1, Math.ceil(pts.length / Math.max(1, Math.floor(iW / 54))));
|
||||||
const allVals = lines.flatMap((l) => pts.map((p) => p[l.key] ?? 0));
|
const allVals = lines.flatMap((l) => pts.map((p) => p[l.key] ?? 0));
|
||||||
const dataMin = Math.min(...allVals);
|
const dataMin = Math.min(...allVals);
|
||||||
const dataMax = Math.max(...allVals);
|
const dataMax = Math.max(...allVals);
|
||||||
@@ -116,7 +118,8 @@ function SvgLineChart({ pts, lines, T, H = 200 }) {
|
|||||||
onleesbare band. De exacte dag staat in de tooltip op elk punt. */}
|
onleesbare band. De exacte dag staat in de tooltip op elk punt. */}
|
||||||
{pts.map((p, i) => {
|
{pts.map((p, i) => {
|
||||||
const laatste = i === pts.length - 1;
|
const laatste = i === pts.length - 1;
|
||||||
if (i % labelStap !== 0 && !laatste) return null;
|
// Terugtellen vanaf het eind, zodat het laatste punt op een stap valt.
|
||||||
|
if ((pts.length - 1 - i) % labelStap !== 0) return null;
|
||||||
return (
|
return (
|
||||||
<g key={i}>
|
<g key={i}>
|
||||||
<line x1={xp(i)} y1={pt2 + iH} x2={xp(i)} y2={pt2 + iH + 4}
|
<line x1={xp(i)} y1={pt2 + iH} x2={xp(i)} y2={pt2 + iH + 4}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vibefinance",
|
"name": "vibefinance",
|
||||||
"version": "1.0.9-dev",
|
"version": "1.0.10",
|
||||||
"description": "VibeFinance — persoonlijk vermogensbeheer",
|
"description": "VibeFinance — persoonlijk vermogensbeheer",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance",
|
"repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance",
|
||||||
|
|||||||
Reference in New Issue
Block a user