aboutsummaryrefslogtreecommitdiff
path: root/web/frontend/official-climb-profile.ts
diff options
context:
space:
mode:
Diffstat (limited to 'web/frontend/official-climb-profile.ts')
-rw-r--r--web/frontend/official-climb-profile.ts53
1 files changed, 35 insertions, 18 deletions
diff --git a/web/frontend/official-climb-profile.ts b/web/frontend/official-climb-profile.ts
index 7e93cc7..72bc8d2 100644
--- a/web/frontend/official-climb-profile.ts
+++ b/web/frontend/official-climb-profile.ts
@@ -1,13 +1,18 @@
-import { officialProfileSections } from "./official-climb-profile-logic.js";
-import type { OfficialProfileSection } from "./official-climb-profile-logic.js";
-import type { OfficialProfileColors, RideProfilePoint } from "./types.js";
+import type {
+ OfficialProfileColors,
+ OfficialProfileSection,
+ ProfileBand,
+ ProfileSectionPayload,
+ RideProfile,
+ RideProfileClimb,
+} from "./types.js";
export class OfficialClimbProfileController {
- readonly points: RideProfilePoint[];
+ readonly climbs: RideProfileClimb[];
readonly colors: OfficialProfileColors;
readonly cards: HTMLDetailsElement[];
- constructor(points: RideProfilePoint[]) {
- this.points = points;
+ constructor(profile: RideProfile) {
+ this.climbs = profile.climbs;
this.colors = this.resolveColors();
this.cards = [...document.querySelectorAll("[data-official-climb-card]")].map((card) => card as HTMLDetailsElement);
for (const card of this.cards) {
@@ -24,18 +29,10 @@ export class OfficialClimbProfileController {
}
drawOfficialProfile(profileCanvas: HTMLCanvasElement): void {
- const { points } = this;
- const startIndex = Number.parseInt(profileCanvas.dataset.profileStart ?? "", 10);
- const endIndex = Number.parseInt(profileCanvas.dataset.profileEnd ?? "", 10);
- if (
- !Number.isInteger(startIndex) ||
- !Number.isInteger(endIndex) ||
- startIndex < 0 ||
- endIndex >= points.length ||
- startIndex >= endIndex
- )
- return;
- const sections = officialProfileSections(points, startIndex, endIndex);
+ const climbIndex = Number.parseInt(profileCanvas.dataset.profileClimbIndex ?? "", 10);
+ const climb = this.climbs.find((candidate) => candidate.index === climbIndex);
+ if (!climb?.sections) return;
+ const sections = officialProfileSections(climb.sections);
if (sections.length === 0) return;
drawOfficialSections(profileCanvas, sections, this.colors);
}
@@ -76,6 +73,26 @@ export function resolveOfficialProfileColors(): OfficialProfileColors {
return colors;
}
+const profileBandForSlope = (slopePercent: number): ProfileBand => {
+ if (slopePercent <= 0) return "downhill";
+ if (slopePercent < 3) return "0-3";
+ if (slopePercent < 6) return "3-6";
+ if (slopePercent < 9) return "6-9";
+ return "9-plus";
+};
+
+// officialProfileSections turns the sections the server cut out of the trace into the chart shape,
+// tagging each step with the band its slope falls in.
+export const officialProfileSections = (sections: ProfileSectionPayload[]): OfficialProfileSection[] =>
+ sections.map((section) => ({
+ startDistanceKm: section.startKm,
+ endDistanceKm: section.endKm,
+ startElevation: section.startElevationM,
+ endElevation: section.endElevationM,
+ slopePercent: section.slopePercent,
+ band: profileBandForSlope(section.slopePercent),
+ }));
+
export interface OfficialProfilePlot {
left: number;
right: number;