summaryrefslogtreecommitdiff
path: root/web/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'web/frontend')
-rw-r--r--web/frontend/ride-detail-canvas.ts4
-rw-r--r--web/frontend/ride-detail-logic.test.ts12
-rw-r--r--web/frontend/ride-detail-logic.ts27
-rw-r--r--web/frontend/types.d.ts2
4 files changed, 25 insertions, 20 deletions
diff --git a/web/frontend/ride-detail-canvas.ts b/web/frontend/ride-detail-canvas.ts
index 1453013..c61afee 100644
--- a/web/frontend/ride-detail-canvas.ts
+++ b/web/frontend/ride-detail-canvas.ts
@@ -1,4 +1,4 @@
-import { clamp, climbMetrics, formatDistance, formatElevation, nearestPointIndex } from "./ride-detail-logic.js";
+import { clamp, climbMetrics, formatClimbLabel, formatDistance, formatElevation, nearestPointIndex } from "./ride-detail-logic.js";
import type { BoundarySource, ClimbBounds, RideDetailColors, RideProfile, RideProfilePoint } from "./types.js";
interface Plot {
@@ -137,7 +137,7 @@ export class RideProfileCanvas {
const endX = clamp(this.xForDistance(metrics.end.distanceKm), plot.left, plot.right);
this.context.fillStyle = climbIndex === this.focusedClimbIndex ? this.colors.climbFocusFill : this.colors.accentFill;
this.context.fillRect(startX, plot.top, Math.max(endX - startX, 1), plot.bottom - plot.top);
- const label = climb.name || `${metrics.category} ${Math.round(metrics.score)}`;
+ const label = formatClimbLabel(climb.name, metrics.category, metrics.cotacol);
this.context.fillStyle = this.colors.climbLabel;
this.context.textAlign = "center";
this.context.textBaseline = "top";
diff --git a/web/frontend/ride-detail-logic.test.ts b/web/frontend/ride-detail-logic.test.ts
index 024f018..b848f7e 100644
--- a/web/frontend/ride-detail-logic.test.ts
+++ b/web/frontend/ride-detail-logic.test.ts
@@ -1,10 +1,11 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
- categoryForScore,
+ categoryForCotacol,
climbMetrics,
cotacolForClimb,
elevationAtDistance,
+ formatClimbLabel,
formatDistance,
formatElevation,
nearestPointIndex,
@@ -28,7 +29,7 @@ test("interpolates elevation between route points", () => {
assert.equal(elevationAtDistance(points, 2, 250), 120);
});
-test("calculates climb metrics with the Cotacol score", () => {
+test("calculates climb metrics with Cotacol", () => {
const metrics = climbMetrics(points, { startIndex: 0, endIndex: 3 });
assert.ok(metrics);
@@ -36,7 +37,12 @@ test("calculates climb metrics with the Cotacol score", () => {
assert.equal(metrics.elevationGain, 20);
assert.equal(metrics.slope, 8);
assert.equal(metrics.cotacol, cotacolForClimb(points, 0, 3));
- assert.equal(metrics.category, categoryForScore(metrics.score));
+ assert.equal(metrics.category, categoryForCotacol(metrics.cotacol));
+});
+
+test("formats profile climb labels with Cotacol", () => {
+ assert.equal(formatClimbLabel("", "Cat 4", 45.9), "Cat 4 45.9");
+ assert.equal(formatClimbLabel("Col de Test", "Cat 4", 45.9), "Col de Test");
});
test("formats profile labels consistently", () => {
diff --git a/web/frontend/ride-detail-logic.ts b/web/frontend/ride-detail-logic.ts
index 825bb2c..a2ba80a 100644
--- a/web/frontend/ride-detail-logic.ts
+++ b/web/frontend/ride-detail-logic.ts
@@ -19,15 +19,17 @@ export const nearestPointIndex = (points: ProfilePoint[], distance: number): num
return distance - previous.distanceKm < points[low].distanceKm - distance ? low - 1 : low;
};
-export const categoryForScore = (score: number): string => {
- if (score < 35) return "NO";
- if (score < 80) return "Cat 4";
- if (score < 180) return "Cat 3";
- if (score < 250) return "Cat 2";
- if (score < 600) return "Cat 1";
+export const categoryForCotacol = (cotacol: number): string => {
+ if (cotacol < 35) return "NO";
+ if (cotacol < 80) return "Cat 4";
+ if (cotacol < 180) return "Cat 3";
+ if (cotacol < 250) return "Cat 2";
+ if (cotacol < 600) return "Cat 1";
return "HC";
};
+export const formatClimbLabel = (name: string, category: string, cotacol: number): string => name || `${category} ${cotacol.toFixed(1)}`;
+
export const elevationAtDistance = (points: ProfilePoint[], index: number, distanceM: number): number => {
if (index + 1 >= points.length) return points[index].elevationM;
const startDistanceM = points[index].distanceKm * 1000;
@@ -40,7 +42,7 @@ export const cotacolForClimb = (points: ProfilePoint[], startIndex: number, endI
const startDistanceM = points[startIndex].distanceKm * 1000;
const lastDistanceM = points[endIndex].distanceKm * 1000;
if (lastDistanceM <= startDistanceM) return 0;
- let score = 0;
+ let cotacol = 0;
let pointIndex = startIndex;
for (let segmentStartM = startDistanceM; segmentStartM < lastDistanceM; segmentStartM += 100) {
const segmentEndM = Math.min(segmentStartM + 100, lastDistanceM);
@@ -49,9 +51,9 @@ export const cotacolForClimb = (points: ProfilePoint[], startIndex: number, endI
while (pointIndex < endIndex && points[pointIndex + 1].distanceKm * 1000 < segmentEndM) pointIndex++;
const endElevation = elevationAtDistance(points, pointIndex, segmentEndM);
const slope = (endElevation - startElevation) / (segmentEndM - segmentStartM);
- if (slope > 0) score += ((segmentEndM - segmentStartM) / 1000) * (slope * 100) ** 2;
+ if (slope > 0) cotacol += ((segmentEndM - segmentStartM) / 1000) * (slope * 100) ** 2;
}
- return score;
+ return cotacol;
};
export const climbMetrics = (points: ProfilePoint[], bounds: ClimbBounds | undefined): ClimbMetrics | null => {
@@ -70,15 +72,14 @@ export const climbMetrics = (points: ProfilePoint[], bounds: ClimbBounds | undef
const distanceKm = end.distanceKm - start.distanceKm;
const elevationGain = end.elevationM - start.elevationM;
const slope = distanceKm > 0 ? elevationGain / (distanceKm * 10) : 0;
- const score = distanceKm > 0 ? ((Math.abs(elevationGain) * elevationGain) / (distanceKm * 1000)) * 10 : 0;
+ const cotacol = cotacolForClimb(points, bounds.startIndex, bounds.endIndex);
return {
start,
end,
distanceKm,
elevationGain,
slope,
- score,
- cotacol: cotacolForClimb(points, bounds.startIndex, bounds.endIndex),
- category: categoryForScore(score),
+ cotacol,
+ category: categoryForCotacol(cotacol),
};
};
diff --git a/web/frontend/types.d.ts b/web/frontend/types.d.ts
index 66f1ad2..3642971 100644
--- a/web/frontend/types.d.ts
+++ b/web/frontend/types.d.ts
@@ -18,7 +18,6 @@ export interface RideProfileClimb {
topKm: number;
topElevationM: number;
name: string;
- score: number;
category: string;
distanceKm: number;
slopePercent: number;
@@ -69,7 +68,6 @@ export interface ClimbMetrics {
distanceKm: number;
elevationGain: number;
slope: number;
- score: number;
cotacol: number;
category: string;
}