blob: 868545b300043d33f28a0e4b0ce31fd0bbda2c1c (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import type { ClimbAttemptPoint } from "./types.js";
// formatAttemptDuration renders an attempt duration as "mm:ss", or "h:mm:ss" past an hour.
export const formatAttemptDuration = (durationS: number): string => {
const total = Math.max(0, Math.round(durationS));
const seconds = total % 60;
const minutes = Math.floor(total / 60) % 60;
const hours = Math.floor(total / 3600);
const two = (value: number): string => String(value).padStart(2, "0");
return hours > 0 ? `${hours}:${two(minutes)}:${two(seconds)}` : `${minutes}:${two(seconds)}`;
};
// formatPower renders an average power in whole watts.
export const formatPower = (powerW: number): string => `${Math.round(powerW)} W`;
export interface AttemptsDomain {
maxDurationS: number;
maxPowerW: number;
}
// attemptsDomain returns zero-based axis bounds padded above the data; empty or degenerate data still yields a drawable unit domain.
export const attemptsDomain = (points: ClimbAttemptPoint[]): AttemptsDomain => {
let maxDurationS = 0;
let maxPowerW = 0;
for (const point of points) {
maxDurationS = Math.max(maxDurationS, point.durationS);
maxPowerW = Math.max(maxPowerW, point.averagePowerW);
}
return { maxDurationS: maxDurationS * 1.08 || 1, maxPowerW: maxPowerW * 1.08 || 1 };
};
|