-
- ${e.wert} ${e.einheit || 'kg'}
-
-
${UI.time.format(e.datum + 'T00:00:00')}
- ${e.notiz ? `
${_esc(e.notiz)}
` : ''}
+
+
+
+ ${UI.time.format(e.datum + 'T00:00:00')}
+
+
+ ${e.wert} ${e.einheit || 'kg'}
+
+ ${e.notiz ? `
${_esc(e.notiz)}
` : ''}
`).join('');
return `
+
+
+ ${latest.wert}
+ kg
+
+ ${deltaHtml}
+
${chart ? `
${chart}
` : ''}
-
${items}
+
${items}
${addBtn}
`;
}
function _weightChart(entries) {
- const W = 320, H = 120, PAD = 24;
- const vals = entries.map(e => parseFloat(e.wert));
- const min = Math.min(...vals);
- const max = Math.max(...vals);
- const range = max - min || 1;
+ const W = 340, H = 160, PX = 36, PY = 16, PB = 28;
+ const vals = entries.map(e => parseFloat(e.wert));
+ const minV = Math.min(...vals);
+ const maxV = Math.max(...vals);
+ const range = maxV - minV || 1;
+ const innerW = W - PX * 2;
+ const innerH = H - PY - PB;
- const pts = entries.map((e, i) => {
- const x = PAD + (i / (entries.length - 1)) * (W - PAD * 2);
- const y = PAD + (1 - (parseFloat(e.wert) - min) / range) * (H - PAD * 2);
- return `${x},${y}`;
- });
+ const toX = i => PX + (i / (entries.length - 1)) * innerW;
+ const toY = v => PY + (1 - (v - minV) / range) * innerH;
+ const pts = entries.map((e, i) => [toX(i), toY(parseFloat(e.wert))]);
- const dots = entries.map((e, i) => {
- const [x, y] = pts[i].split(',');
- return `
`;
+ // Smooth bezier path
+ const linePath = pts.reduce((acc, [x, y], i) => {
+ if (i === 0) return `M ${x},${y}`;
+ const [px, py] = pts[i - 1];
+ const cpx = (px + x) / 2;
+ return `${acc} C ${cpx},${py} ${cpx},${y} ${x},${y}`;
+ }, '');
+
+ const fillPath = `${linePath} L ${pts[pts.length - 1][0]},${H - PB} L ${pts[0][0]},${H - PB} Z`;
+
+ // Grid lines
+ const gridLines = [0, 0.5, 1].map(frac => {
+ const v = maxV - frac * range;
+ const y = toY(v);
+ return `
+
+
+ ${v.toFixed(1)}
+ `;
}).join('');
- const labels = [
- `
${entries[0].datum.slice(5)}`,
- `
${entries[entries.length - 1].datum.slice(5)}`,
- `
${max.toFixed(1)}`,
- `
${min.toFixed(1)}`,
- ].join('');
+ // X-axis labels
+ const xIdxs = entries.length <= 3
+ ? entries.map((_, i) => i)
+ : [0, Math.round((entries.length - 1) / 2), entries.length - 1];
+ const xLabels = [...new Set(xIdxs)].map(i => {
+ const [m, d] = entries[i].datum.slice(5).split('-');
+ return `
${d}.${m}.`;
+ }).join('');
+ // Dots
+ const dots = pts.map(([x, y], i) => {
+ const isLast = i === pts.length - 1;
+ return `
`;
+ }).join('');
+
+ const gId = `wg${Math.random().toString(36).slice(2, 7)}`;
return `
-
`;
- UI.modal.open({ title: `${tabInfo.icon} ${_esc(entry.bezeichnung)}`, body });
+ const modalTitle = entry.typ === 'gewicht'
+ ? `${tabInfo.icon} ${entry.wert} ${entry.einheit || 'kg'}`
+ : `${tabInfo.icon} ${_esc(entry.bezeichnung)}`;
+ UI.modal.open({ title: modalTitle, body });
document.getElementById('health-detail-edit')?.addEventListener('click', () => {
UI.modal.close();
@@ -538,12 +600,13 @@ window.Page_health = (() => {
const t = typ || _activeTab;
const commonFields = `
-