fix: [BUG-003] correlations chart shows all weight data with extrapolation
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

Changes:
- Show all data points (kcal OR weight, not only both)
- Extrapolate missing kcal values at end (use last known value)
- Dashed lines (strokeDasharray) for extrapolated values
- Solid lines for real measurements
- Weight always interpolates gaps (connectNulls=true)

Visual distinction:
- Solid = Real measurements + gap interpolation
- Dashed = Extrapolation at chart end

Closes: BUG-003

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-21 09:51:20 +01:00
parent d1675dcc80
commit 888b5c3e40

View File

@ -598,26 +598,62 @@ function OverviewCards({ data }) {
// Chart: Kalorien vs Gewicht
function CaloriesVsWeight({ data }) {
const filtered = data.filter(d => d.kcal && d.weight)
const withAvg = rollingAvg(filtered.map(d=>({...d,date:dayjs(d.date).format('DD.MM')})), 'kcal')
// BUG-003 fix: Show all weight data, extrapolate kcal if missing
const filtered = data.filter(d => d.kcal || d.weight)
if (filtered.length < 3) return (
<div style={{padding:20,textAlign:'center',color:'var(--text3)',fontSize:13}}>
Zu wenig gemeinsame Daten (Gewicht + Kalorien am selben Tag nötig)
Zu wenig Daten für diese Auswertung
</div>
)
// Find last real kcal value
const lastKcalIndex = filtered.findLastIndex(d => d.kcal)
const lastKcal = lastKcalIndex >= 0 ? filtered[lastKcalIndex].kcal : null
// Extrapolate missing kcal values at the end
const withExtrapolated = filtered.map((d, i) => ({
...d,
kcal: d.kcal || (i > lastKcalIndex && lastKcal ? lastKcal : null),
isKcalExtrapolated: !d.kcal && i > lastKcalIndex && lastKcal
}))
// Format dates and calculate rolling average
const formatted = withExtrapolated.map(d => ({
...d,
date: dayjs(d.date).format('DD.MM')
}))
const withAvg = rollingAvg(formatted, 'kcal')
// Split into real and extrapolated segments for dashed lines
const realData = withAvg.map(d => ({
...d,
kcal_extrap: d.isKcalExtrapolated ? d.kcal : null,
kcal_avg_extrap: d.isKcalExtrapolated ? d.kcal_avg : null,
kcal: d.isKcalExtrapolated ? null : d.kcal,
kcal_avg: d.isKcalExtrapolated ? null : d.kcal_avg
}))
return (
<ResponsiveContainer width="100%" height={220}>
<LineChart data={withAvg} margin={{top:4,right:8,bottom:0,left:-16}}>
<LineChart data={realData} margin={{top:4,right:8,bottom:0,left:-16}}>
<CartesianGrid stroke="var(--border)" strokeDasharray="3 3"/>
<XAxis dataKey="date" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false}
interval={Math.max(0,Math.floor(withAvg.length/6)-1)}/>
interval={Math.max(0,Math.floor(realData.length/6)-1)}/>
<YAxis yAxisId="kcal" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false} domain={['auto','auto']}/>
<YAxis yAxisId="weight" orientation="right" tick={{fontSize:9,fill:'var(--text3)'}} tickLine={false} domain={['auto','auto']}/>
<Tooltip contentStyle={{background:'var(--surface)',border:'1px solid var(--border)',borderRadius:8,fontSize:11}}
formatter={(v,n)=>[`${Math.round(v)} ${n==='weight'?'kg':'kcal'}`, n==='kcal_avg'?'Ø 7T Kalorien':n==='weight'?'Gewicht':'Kalorien']}/>
<Line yAxisId="kcal" type="monotone" dataKey="kcal" stroke="#EF9F2744" strokeWidth={1} dot={false}/>
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg" stroke="#EF9F27" strokeWidth={2} dot={false} name="kcal_avg"/>
<Line yAxisId="weight" type="monotone" dataKey="weight" stroke="#378ADD" strokeWidth={2} dot={{r:3,fill:'#378ADD'}} name="weight"/>
formatter={(v,n)=>[`${Math.round(v)} ${n==='weight'?'kg':'kcal'}`, n.includes('avg')?'Ø 7T Kalorien':n==='weight'?'Gewicht':'Kalorien']}/>
{/* Real kcal values - solid lines */}
<Line yAxisId="kcal" type="monotone" dataKey="kcal" stroke="#EF9F2744" strokeWidth={1} dot={false} connectNulls={false}/>
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg" stroke="#EF9F27" strokeWidth={2} dot={false} name="kcal_avg" connectNulls={false}/>
{/* Extrapolated kcal values - dashed lines */}
<Line yAxisId="kcal" type="monotone" dataKey="kcal_extrap" stroke="#EF9F2744" strokeWidth={1} strokeDasharray="3 3" dot={false} connectNulls={false}/>
<Line yAxisId="kcal" type="monotone" dataKey="kcal_avg_extrap" stroke="#EF9F27" strokeWidth={2} strokeDasharray="3 3" dot={false} connectNulls={false}/>
{/* Weight - always solid */}
<Line yAxisId="weight" type="monotone" dataKey="weight" stroke="#378ADD" strokeWidth={2} dot={{r:3,fill:'#378ADD'}} name="weight" connectNulls={true}/>
</LineChart>
</ResponsiveContainer>
)