feat: add fat mass + muscle mass curves to chart, limit to last 30 days

This commit is contained in:
Eddy de Vink 2026-06-27 23:48:13 +02:00
commit 1275a229f2

View file

@ -5,6 +5,12 @@ import { Measurement } from '../types'
type Props = { measurements: Measurement[] } type Props = { measurements: Measurement[] }
const COLORS = {
weight: '#4CAF50',
fatMass: '#FF9800',
muscleMass: '#2196F3',
}
export default function WeightChart({ measurements }: Props) { export default function WeightChart({ measurements }: Props) {
if (measurements.length < 2) { if (measurements.length < 2) {
return null return null
@ -14,34 +20,72 @@ export default function WeightChart({ measurements }: Props) {
(a, b) => new Date(a.measuredAt).getTime() - new Date(b.measuredAt).getTime() (a, b) => new Date(a.measuredAt).getTime() - new Date(b.measuredAt).getTime()
) )
const labels = sorted.map(m => { const cutoff = new Date(sorted[sorted.length - 1].measuredAt)
cutoff.setDate(cutoff.getDate() - 30)
const filtered = sorted.filter(m => new Date(m.measuredAt) >= cutoff)
const dataPoints = filtered.length >= 2 ? filtered : sorted
const labels = dataPoints.map(m => {
const d = new Date(m.measuredAt) const d = new Date(m.measuredAt)
return `${d.getDate()}/${d.getMonth() + 1}` return `${d.getDate()}/${d.getMonth() + 1}`
}) })
const data = sorted.map(m => m.weight)
const labelStep = labels.length > 8 ? Math.ceil(labels.length / 8) : 1
const sparseLabels = labels.map((l, i) => (i % labelStep === 0 ? l : ''))
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.title}>Gewichtsgrafiek</Text> <Text style={styles.title}>Gewicht & Lichaamssamenstelling</Text>
<LineChart <LineChart
data={{ data={{
labels: labels.length > 10 ? labels.filter((_, i) => i % Math.ceil(labels.length / 10) === 0) : labels, labels: sparseLabels,
datasets: [{ data }], datasets: [
{
data: dataPoints.map(m => m.weight),
color: () => COLORS.weight,
strokeWidth: 2,
},
{
data: dataPoints.map(m => m.fatMass),
color: () => COLORS.fatMass,
strokeWidth: 2,
},
{
data: dataPoints.map(m => m.muscleMass),
color: () => COLORS.muscleMass,
strokeWidth: 2,
},
],
}} }}
width={Dimensions.get('window').width - 32} width={Dimensions.get('window').width - 32}
height={220} height={240}
yAxisSuffix=" kg" yAxisSuffix=" kg"
chartConfig={{ chartConfig={{
backgroundColor: '#ffffff', backgroundColor: '#ffffff',
backgroundGradientFrom: '#ffffff', backgroundGradientFrom: '#ffffff',
backgroundGradientTo: '#ffffff', backgroundGradientTo: '#ffffff',
decimalPlaces: 1, decimalPlaces: 1,
color: (opacity = 1) => `rgba(76, 175, 80, ${opacity})`, color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
labelColor: () => '#666', labelColor: () => '#666',
propsForDots: { r: '3' },
}} }}
bezier bezier
style={styles.chart} style={styles.chart}
/> />
<View style={styles.legend}>
<View style={styles.legendItem}>
<View style={[styles.legendDot, { backgroundColor: COLORS.weight }]} />
<Text style={styles.legendLabel}>Gewicht</Text>
</View>
<View style={styles.legendItem}>
<View style={[styles.legendDot, { backgroundColor: COLORS.fatMass }]} />
<Text style={styles.legendLabel}>Vetmassa</Text>
</View>
<View style={styles.legendItem}>
<View style={[styles.legendDot, { backgroundColor: COLORS.muscleMass }]} />
<Text style={styles.legendLabel}>Spiermassa</Text>
</View>
</View>
</View> </View>
) )
} }
@ -50,4 +94,8 @@ const styles = StyleSheet.create({
container: { marginHorizontal: 16, marginBottom: 16 }, container: { marginHorizontal: 16, marginBottom: 16 },
title: { fontSize: 18, fontWeight: '700', marginBottom: 8 }, title: { fontSize: 18, fontWeight: '700', marginBottom: 8 },
chart: { borderRadius: 12 }, chart: { borderRadius: 12 },
legend: { flexDirection: 'row', justifyContent: 'center', gap: 16, marginTop: 8 },
legendItem: { flexDirection: 'row', alignItems: 'center', gap: 4 },
legendDot: { width: 10, height: 10, borderRadius: 5 },
legendLabel: { fontSize: 12, color: '#666' },
}) })