diff options
Diffstat (limited to 'web/frontend/climb-attempts-logic.ts')
| -rw-r--r-- | web/frontend/climb-attempts-logic.ts | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/web/frontend/climb-attempts-logic.ts b/web/frontend/climb-attempts-logic.ts new file mode 100644 index 0000000..868545b --- /dev/null +++ b/web/frontend/climb-attempts-logic.ts @@ -0,0 +1,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 }; +}; |
