Track detail: HR chart as its own collapsible section + 'what if by HR' kcal comparison
- Speed/Elevation/Пульс are now collapsible <details> sections; the HR chart
moved out of the Elevation block into its own 'Пульс' section (avg/max + chart),
shown when the track has HR.
- Калории now also shows the Keytel HR-based kcal as a COMPARISON when HR is
present ('По ЧСС (сравнение)'). The activity balance keeps the physics/MET
number unchanged - this is only to see the difference.
This commit is contained in:
parent
87a7fccfcc
commit
1df24000a3
1 changed files with 34 additions and 8 deletions
|
|
@ -5468,6 +5468,21 @@ async function showSessionDetail(sessionId) {
|
|||
: "—";
|
||||
let kcalMin = stats.duration > 0 ? (stats.kcal / (stats.duration / 60)).toFixed(1) : "—";
|
||||
|
||||
// HR-based kcal "what if" (Keytel) — comparison ONLY. The activity balance keeps the physics/MET
|
||||
// number (don't disturb the established diet); here we just show what HR would give, if present.
|
||||
let _t0hr = points.length ? new Date(points[0].ts).getTime() : 0;
|
||||
let hrSamples = points.filter(p => p.heart_rate > 0).map(p => [(new Date(p.ts).getTime() - _t0hr) / 1000, p.heart_rate]);
|
||||
let hasHr = hrSamples.length > 2;
|
||||
let hrProfile = {
|
||||
weightKg: session.rider_weight_kg ?? state.latestWeight?.weight_kg ?? state.profile?.weight_kg ?? 75,
|
||||
age: BMR.getAge(parseInt(state.profile?.birth_year) || 1988),
|
||||
sex: state.profile?.sex || "m",
|
||||
heightCm: parseFloat(state.profile?.height_cm) || 178,
|
||||
};
|
||||
let hrKcal = hasHr ? GPS.hrKcalNet(hrSamples, hrProfile) : null;
|
||||
let hrAvg = hasHr ? Math.round(hrSamples.reduce((a, s) => a + s[1], 0) / hrSamples.length) : null;
|
||||
let hrMax = hasHr ? Math.max(...hrSamples.map(s => s[1])) : null;
|
||||
|
||||
showModal(`
|
||||
<h3>${actName}</h3>
|
||||
<div id="sd-track-id" style="font-size:11px;color:var(--muted);margin:-6px 0 8px;cursor:pointer;user-select:all">ID: ${session.id}</div>
|
||||
|
|
@ -5493,27 +5508,29 @@ async function showSessionDetail(sessionId) {
|
|||
<div id="sd-map" class="sd-map"></div>
|
||||
</div>
|
||||
|
||||
<div class="sd-section">
|
||||
<div class="sd-title">Скорость</div>
|
||||
<details class="sd-section sd-accordion" open>
|
||||
<summary class="sd-title sd-acc-title">Скорость</summary>
|
||||
<div class="sd-row">
|
||||
<div class="sd-stat"><span class="sd-val">${stats.avgSpeed} км/ч</span><span class="sd-lbl">Средняя</span></div>
|
||||
<div class="sd-stat"><span class="sd-val" id="sd-max-speed">${stats.maxSpeed} км/ч</span><span class="sd-lbl">Макс.</span></div>
|
||||
</div>
|
||||
<div id="sd-walk-stat" class="prod-hint" style="text-align:center;margin-bottom:6px"></div>
|
||||
<div class="chart-wrap" id="sd-speed-wrap"><canvas id="sd-speed-chart" height="150" style="touch-action:pan-y"></canvas></div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="sd-section">
|
||||
<div class="sd-title">Калории</div>
|
||||
<div class="sd-row">
|
||||
<div class="sd-stat"><span class="sd-val">${session.total_kcal ?? stats.kcal} ккал</span><span class="sd-lbl">Всего</span></div>
|
||||
<div class="sd-stat"><span class="sd-val">${session.total_kcal ?? stats.kcal} ккал</span><span class="sd-lbl">${hasHr ? "Физика (в баланс)" : "Всего"}</span></div>
|
||||
<div class="sd-stat"><span class="sd-val">${kcalMin} ккал/мин</span><span class="sd-lbl">Расход</span></div>
|
||||
</div>
|
||||
${hasHr ? `<div class="sd-row"><div class="sd-stat"><span class="sd-val">${hrKcal} ккал</span><span class="sd-lbl">По ЧСС (сравнение)</span></div></div>
|
||||
<div class="prod-hint" style="text-align:center;margin-top:4px">В баланс идёт «физика»; цифра по ЧСС (Keytel) - для сравнения.</div>` : ""}
|
||||
</div>
|
||||
|
||||
${elevations.length > 0 ? `
|
||||
<div class="sd-section">
|
||||
<div class="sd-title">Высота</div>
|
||||
<details class="sd-section sd-accordion" open>
|
||||
<summary class="sd-title sd-acc-title">Высота</summary>
|
||||
<div class="sd-row">
|
||||
<div class="sd-stat"><span class="sd-val">${minElev} м</span><span class="sd-lbl">Мин.</span></div>
|
||||
<div class="sd-stat"><span class="sd-val">${maxElev} м</span><span class="sd-lbl">Макс.</span></div>
|
||||
|
|
@ -5523,8 +5540,17 @@ async function showSessionDetail(sessionId) {
|
|||
<div class="sd-stat"><span class="sd-val">${stats.elevLoss} м</span><span class="sd-lbl">Спуск</span></div>
|
||||
</div>
|
||||
<div class="chart-wrap" id="sd-elev-wrap"><canvas id="sd-elev-chart" height="150" style="touch-action:pan-y"></canvas></div>
|
||||
<div class="chart-wrap" id="sd-hr-wrap" style="display:none"><canvas id="sd-hr-chart" height="150" style="touch-action:pan-y"></canvas></div>
|
||||
</div>` : ""}
|
||||
</details>` : ""}
|
||||
|
||||
${hasHr ? `
|
||||
<details class="sd-section sd-accordion" open>
|
||||
<summary class="sd-title sd-acc-title">Пульс</summary>
|
||||
<div class="sd-row">
|
||||
<div class="sd-stat"><span class="sd-val">${hrAvg}</span><span class="sd-lbl">Средний</span></div>
|
||||
<div class="sd-stat"><span class="sd-val">${hrMax}</span><span class="sd-lbl">Макс.</span></div>
|
||||
</div>
|
||||
<div class="chart-wrap" id="sd-hr-wrap"><canvas id="sd-hr-chart" height="150" style="touch-action:pan-y"></canvas></div>
|
||||
</details>` : ""}
|
||||
|
||||
${(stats.segments && stats.segments.length > 1) ? `
|
||||
<details class="sd-section sd-accordion">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue