summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-16 14:55:26 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-16 14:55:26 +0200
commitdf7c9b5130ba193fc918a947a461f2a70dc2dd3c (patch)
tree0366e0b60338e268d758511621b9adf721be8322
parent53ab332e6d2afe9818914e0026310e4cadcc4202 (diff)
fix(web): use Cotacol for climb difficulty
-rw-r--r--ride/.snapshots/TestRideClimbLaCride6
-rw-r--r--ride/climb.go47
-rw-r--r--ride/climb_test.go42
-rw-r--r--ride/ride.go21
-rw-r--r--rideanalysis/analysis.go8
-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
-rw-r--r--web/server.go6
-rw-r--r--web/server_test.go1
-rw-r--r--web/views.go10
12 files changed, 84 insertions, 102 deletions
diff --git a/ride/.snapshots/TestRideClimbLaCride b/ride/.snapshots/TestRideClimbLaCride
index 456818e..d81ca17 100644
--- a/ride/.snapshots/TestRideClimbLaCride
+++ b/ride/.snapshots/TestRideClimbLaCride
@@ -1,5 +1,5 @@
([]string) (len=3) {
- (string) (len=69) "Climb 17.1km-18.8km: 1.7km at 4.8% (38 pts - Cat 4) (5m50s, 17.0km/h)",
- (string) (len=65) " 17.2km-18.8km: 1.6km at 4.9% (38 pts - Cat 4) (7m42s, 12.8km/h)",
- (string) (len=70) "Climb 35.1km-40.1km: 5.1km at 4.3% (94 pts - Cat 3) (18m48s, 16.2km/h)"
+ (string) (len=69) "Climb 17.1km-18.8km: 1.7km at 4.8% (45 pts - Cat 4) (5m50s, 17.0km/h)",
+ (string) (len=65) " 17.2km-18.8km: 1.6km at 4.9% (45 pts - Cat 4) (7m42s, 12.8km/h)",
+ (string) (len=71) "Climb 35.1km-40.1km: 5.1km at 4.3% (126 pts - Cat 3) (18m48s, 16.2km/h)"
}
diff --git a/ride/climb.go b/ride/climb.go
index 788cd61..56e47c6 100644
--- a/ride/climb.go
+++ b/ride/climb.go
@@ -79,18 +79,14 @@ func (climb Climb) TopCoord() geodist.Coord {
func (climb Climb) String() string {
startDistance := climb.StartDistanceM()
endDistance := climb.EndDistanceM()
- score := climb.Score()
- body := fmt.Sprintf("%.1fkm-%.1fkm: %.1fkm at %.1f%% (%d pts - %s)", startDistance/1000, endDistance/1000, (endDistance-startDistance)/1000, Slope(climb.ride, climb.rideStart, climb.rideEnd)*100, int(score), Category(score))
+ cotacol := climb.DifficultyScore()
+ body := fmt.Sprintf("%.1fkm-%.1fkm: %.1fkm at %.1f%% (%d pts - %s)", startDistance/1000, endDistance/1000, (endDistance-startDistance)/1000, Slope(climb.ride, climb.rideStart, climb.rideEnd)*100, int(cotacol), Category(cotacol))
if climb.Name == "" {
return body
}
return climb.Name + ": " + body
}
-func (climb Climb) Score() float64 {
- return Score(climb.ride, climb.rideStart, climb.rideEnd)
-}
-
func (climb Climb) DifficultyScore() float64 {
return difficultyScore(climb.ride, climb.rideStart, climb.rideEnd)
}
@@ -99,28 +95,27 @@ func Slope(r Ride, start, end int) float64 {
return (r.ElevationM(end) - r.ElevationM(start)) / (r.DistanceM(end) - r.DistanceM(start))
}
-func Score(r Ride, start, end int) float64 {
- kcore.Assert(end > start, "no points for score")
+func climbDetectionScore(r Ride, start, end int) float64 {
+ kcore.Assert(end > start, "no points for climb detection")
distance := r.DistanceM(end) - r.DistanceM(start)
if distance == 0 {
return 0
}
dElevation := r.ElevationM(end) - r.ElevationM(start)
-
return math.Abs(dElevation) * dElevation / distance * 100.0 * 100.0 / 1000.0
}
-func Category(score float64) string {
+func Category(cotacol float64) string {
switch {
- case score < 35:
+ case cotacol < 35:
return "NO"
- case score < 80:
+ case cotacol < 80:
return "Cat 4"
- case score < 180:
+ case cotacol < 180:
return "Cat 3"
- case score < 250:
+ case cotacol < 250:
return "Cat 2"
- case score < 600:
+ case cotacol < 600:
return "Cat 1"
default:
return "HC"
@@ -130,28 +125,28 @@ func Category(score float64) string {
func bestClimbBetween(r Ride, start, end int) Climb {
kcore.Assert(end > start, "empty points")
- bestScore := Score(r, start, end)
+ bestDetectionScore := climbDetectionScore(r, start, end)
bestStart := start
for i := start; i < end; i++ {
- score := Score(r, i, end)
- if score > bestScore {
+ detectionScore := climbDetectionScore(r, i, end)
+ if detectionScore > bestDetectionScore {
bestStart = i
- bestScore = score
+ bestDetectionScore = detectionScore
}
}
bestEnd := end
for i := end; i > bestStart; i-- {
- score := Score(r, bestStart, i)
- if score > bestScore {
+ detectionScore := climbDetectionScore(r, bestStart, i)
+ if detectionScore > bestDetectionScore {
bestEnd = i
- bestScore = score
+ bestDetectionScore = detectionScore
}
}
for i := bestStart; i < bestEnd; i++ {
- score := Score(r, i, bestEnd)
- if score > bestScore {
+ detectionScore := climbDetectionScore(r, i, bestEnd)
+ if detectionScore > bestDetectionScore {
bestStart = i
- bestScore = score
+ bestDetectionScore = detectionScore
}
}
kcore.Assert(bestStart < bestEnd, "empty climb")
@@ -175,7 +170,7 @@ func climbsBetween(r Ride, start, end int) []Climb {
return climbsBetween(r, start+1, end)
}
climb := bestClimbBetween(r, start, highest)
- if climb.Score() >= 35 && climb.EndDistanceM()-climb.StartDistanceM() >= ClimbDistanceMinimum {
+ if climbDetectionScore(r, climb.rideStart, climb.rideEnd) >= 35 && climb.EndDistanceM()-climb.StartDistanceM() >= ClimbDistanceMinimum {
slog.Debug("Found climb between", slog.Int("start", int(climb.StartDistanceM())), slog.Int("end", int(climb.EndDistanceM())))
climbs = append(climbs, climb)
}
diff --git a/ride/climb_test.go b/ride/climb_test.go
index 3dd6e53..feca001 100644
--- a/ride/climb_test.go
+++ b/ride/climb_test.go
@@ -86,12 +86,12 @@ func TestPogacar20220721(t *testing.T) {
climbs := r.AllClimbs()
assert.Len(t, climbs, 6)
- assert.Equal(t, "0.6km-5.6km: 5.0km at 3.5% (62 pts - Cat 4)", climbs[0].String())
- assert.Equal(t, "42.9km-45.2km: 2.3km at 5.0% (59 pts - Cat 4)", climbs[1].String())
- assert.Equal(t, "60.0km-76.4km: 16.4km at 7.2% (854 pts - HC)", climbs[2].String())
- assert.Equal(t, "83.8km-85.9km: 2.0km at 5.4% (59 pts - Cat 4)", climbs[3].String())
- assert.Equal(t, "99.2km-109.3km: 10.2km at 8.4% (710 pts - HC)", climbs[4].String())
- assert.Equal(t, "128.6km-142.2km: 13.6km at 7.8% (832 pts - HC)", climbs[5].String())
+ assert.Equal(t, "0.6km-5.6km: 5.0km at 3.5% (92 pts - Cat 3)", climbs[0].String())
+ assert.Equal(t, "42.9km-45.2km: 2.3km at 5.0% (74 pts - Cat 4)", climbs[1].String())
+ assert.Equal(t, "60.0km-76.4km: 16.4km at 7.2% (977 pts - HC)", climbs[2].String())
+ assert.Equal(t, "83.8km-85.9km: 2.0km at 5.4% (79 pts - Cat 4)", climbs[3].String())
+ assert.Equal(t, "99.2km-109.3km: 10.2km at 8.4% (751 pts - HC)", climbs[4].String())
+ assert.Equal(t, "128.6km-142.2km: 13.6km at 7.8% (930 pts - HC)", climbs[5].String())
}
func TestBouclesVerdon2024(t *testing.T) {
@@ -100,12 +100,12 @@ func TestBouclesVerdon2024(t *testing.T) {
climbs := r.AllClimbs()
assert.Len(t, climbs, 6)
- assert.Equal(t, "3.6km-13.8km: 10.3km at 2.1% (44 pts - Cat 4)", climbs[0].String()) // TODO: Not steep enough
- assert.Equal(t, "34.7km-37.3km: 2.5km at 5.0% (62 pts - Cat 4)", climbs[1].String())
- assert.Equal(t, "41.9km-51.0km: 9.0km at 2.5% (55 pts - Cat 4)", climbs[2].String()) // TODO: Not steep enough
- assert.Equal(t, "57.6km-60.8km: 3.1km at 6.3% (124 pts - Cat 3)", climbs[3].String())
- assert.Equal(t, "71.7km-74.7km: 3.0km at 5.3% (84 pts - Cat 3)", climbs[4].String())
- assert.Equal(t, "77.4km-78.7km: 1.3km at 5.3% (37 pts - Cat 4)", climbs[5].String())
+ assert.Equal(t, "3.6km-13.8km: 10.3km at 2.1% (98 pts - Cat 3)", climbs[0].String()) // TODO: Not steep enough
+ assert.Equal(t, "34.7km-37.3km: 2.5km at 5.0% (67 pts - Cat 4)", climbs[1].String())
+ assert.Equal(t, "41.9km-51.0km: 9.0km at 2.5% (113 pts - Cat 3)", climbs[2].String()) // TODO: Not steep enough
+ assert.Equal(t, "57.6km-60.8km: 3.1km at 6.3% (139 pts - Cat 3)", climbs[3].String())
+ assert.Equal(t, "71.7km-74.7km: 3.0km at 5.3% (89 pts - Cat 3)", climbs[4].String())
+ assert.Equal(t, "77.4km-78.7km: 1.3km at 5.3% (39 pts - Cat 4)", climbs[5].String())
}
func TestMimetArbois20241229(t *testing.T) {
@@ -114,8 +114,8 @@ func TestMimetArbois20241229(t *testing.T) {
climbs := r.AllClimbs()
assert.Len(t, climbs, 2)
- assert.Equal(t, "3.9km-5.3km: 1.4km at 10.3% (153 pts - Cat 3)", climbs[0].String())
- assert.Equal(t, "14.4km-19.8km: 5.4km at 4.3% (98 pts - Cat 3)", climbs[1].String())
+ assert.Equal(t, "3.9km-5.3km: 1.4km at 10.3% (165 pts - Cat 3)", climbs[0].String())
+ assert.Equal(t, "14.4km-19.8km: 5.4km at 4.3% (113 pts - Cat 3)", climbs[1].String())
}
func TestMimetArbois20250104(t *testing.T) {
@@ -124,8 +124,8 @@ func TestMimetArbois20250104(t *testing.T) {
climbs := r.AllClimbs()
assert.Len(t, climbs, 2)
- assert.Equal(t, "4.5km-5.9km: 1.4km at 10.1% (148 pts - Cat 3)", climbs[0].String())
- assert.Equal(t, "12.0km-20.2km: 8.2km at 2.9% (67 pts - Cat 4)", climbs[1].String()) // TODO: Not steep enough
+ assert.Equal(t, "4.5km-5.9km: 1.4km at 10.1% (159 pts - Cat 3)", climbs[0].String())
+ assert.Equal(t, "12.0km-20.2km: 8.2km at 2.9% (148 pts - Cat 3)", climbs[1].String()) // TODO: Not steep enough
}
// https://www.strava.com/activities/9282265844
@@ -135,10 +135,10 @@ func TestAlpesVerdonTour20230617(t *testing.T) {
climbs := r.AllClimbs()
assert.Len(t, climbs, 6)
- assert.Equal(t, "0.7km-18.6km: 17.9km at 3.5% (217 pts - Cat 2)", climbs[0].String()) // TODO: Should split in 2 (10km at 4.5% is Cat 2)
- assert.Equal(t, "36.1km-41.6km: 5.4km at 5.8% (182 pts - Cat 2)", climbs[1].String())
+ assert.Equal(t, "0.7km-18.6km: 17.9km at 3.5% (364 pts - Cat 1)", climbs[0].String()) // TODO: Should split in 2 (10km at 4.5% is Cat 2)
+ assert.Equal(t, "36.1km-41.6km: 5.4km at 5.8% (193 pts - Cat 2)", climbs[1].String())
assert.Equal(t, "47.0km-48.2km: 1.2km at 6.1% (45 pts - Cat 4)", climbs[2].String())
- assert.Equal(t, "51.9km-54.7km: 2.8km at 4.0% (45 pts - Cat 4)", climbs[3].String())
- assert.Equal(t, "86.7km-92.8km: 6.1km at 2.7% (44 pts - Cat 4)", climbs[4].String())
- assert.Equal(t, "114.1km-114.7km: 0.6km at 14.3% (118 pts - Cat 3)", climbs[5].String())
+ assert.Equal(t, "51.9km-54.7km: 2.8km at 4.0% (48 pts - Cat 4)", climbs[3].String())
+ assert.Equal(t, "86.7km-92.8km: 6.1km at 2.7% (60 pts - Cat 4)", climbs[4].String())
+ assert.Equal(t, "114.1km-114.7km: 0.6km at 14.3% (119 pts - Cat 3)", climbs[5].String())
}
diff --git a/ride/ride.go b/ride/ride.go
index 3458483..152bca4 100644
--- a/ride/ride.go
+++ b/ride/ride.go
@@ -226,21 +226,6 @@ func metricValue(point gpx.GPXPoint, name string) (*float64, error) {
return &value, nil
}
-func (r *Ride) ScoreFromKm(start, end float64) float64 {
- i := 0
- j := 0
- for k, distance := range r.distances {
- if i == 0 && distance >= start*1000 {
- i = k
- }
- if j == 0 && distance >= end*1000 {
- j = k
- break
- }
- }
- return Score(*r, i, j)
-}
-
const CotacolAlgorithmVersion = "v1"
func Cotacol(ride Ride) float64 {
@@ -256,7 +241,7 @@ func difficultyScore(r Ride, startIndex, endIndex int) float64 {
if lastDistance <= startDistance {
return 0
}
- score := 0.0
+ cotacol := 0.0
i := startIndex
for start := startDistance; start < lastDistance; start += 100 {
end := math.Min(start+100, lastDistance)
@@ -270,10 +255,10 @@ func difficultyScore(r Ride, startIndex, endIndex int) float64 {
endElevation := interpolateElevation(r, i, end)
slope := (endElevation - startElevation) / (end - start)
if slope > 0 {
- score += (end - start) / 1000 * (slope * 100) * (slope * 100)
+ cotacol += (end - start) / 1000 * (slope * 100) * (slope * 100)
}
}
- return score
+ return cotacol
}
func interpolateElevation(r Ride, i int, distance float64) float64 {
diff --git a/rideanalysis/analysis.go b/rideanalysis/analysis.go
index 3d34855..122a29f 100644
--- a/rideanalysis/analysis.go
+++ b/rideanalysis/analysis.go
@@ -17,7 +17,6 @@ type Result struct {
type AnalyzedClimb struct {
Segment ride.Climb
Name string
- Score float64
Category string
DistanceM float64
SlopePercent float64
@@ -48,15 +47,14 @@ func Analyze(parsed ride.Ride, passes []mountain_pass.MountainPass, officialClim
matchedOfficial = official_climb.OfficialClimb{}
}
}
- score := displayClimb.Score()
+ cotacol := displayClimb.DifficultyScore()
result.Climbs = append(result.Climbs, AnalyzedClimb{
Segment: displayClimb,
Name: displayClimb.Name,
- Score: score,
- Category: ride.Category(score),
+ Category: ride.Category(cotacol),
DistanceM: displayClimb.EndDistanceM() - displayClimb.StartDistanceM(),
SlopePercent: ride.Slope(parsed, displayClimb.StartIndex(), displayClimb.EndIndex()) * 100,
- Cotacol: displayClimb.DifficultyScore(),
+ Cotacol: cotacol,
OfficialClimbID: officialClimbID(matchedOfficial, officialFound),
OfficialName: officialClimbName(matchedOfficial, officialFound),
})
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;
}
diff --git a/web/server.go b/web/server.go
index 5d5e239..42ee21d 100644
--- a/web/server.go
+++ b/web/server.go
@@ -218,10 +218,10 @@ func buildRideViews(items []rides.Ride) []RideView {
func buildRideView(item rides.Ride) RideView {
view := RideView{Ride: item, Cotacol: "-", CotacolPer100Km: "-"}
- score, ready := item.CotacolScore()
+ cotacol, ready := item.CotacolScore()
if ready && item.CotacolAlgorithmVersion() == ride.CotacolAlgorithmVersion && item.DistanceM > 0 {
- view.Cotacol = formatCotacol(score)
- view.CotacolPer100Km = formatCotacolPer100Km(score, item.DistanceM)
+ view.Cotacol = formatCotacol(cotacol)
+ view.CotacolPer100Km = formatCotacolPer100Km(cotacol, item.DistanceM)
}
return view
}
diff --git a/web/server_test.go b/web/server_test.go
index 654d6d5..f719372 100644
--- a/web/server_test.go
+++ b/web/server_test.go
@@ -151,6 +151,7 @@ func TestHandlerRendersRideDetailWithEmbeddedRoute(t *testing.T) {
assert.Contains(t, body, `"type":"FeatureCollection"`)
assert.Contains(t, body, `"type":"LineString"`)
assert.Contains(t, body, `"coordinates":[[5,43]`)
+ assert.NotContains(t, body, `"score":`)
profileStaticRequest := httptest.NewRequest(http.MethodGet, "/static/official-climb-profile.js", nil)
profileStaticResponse := httptest.NewRecorder()
diff --git a/web/views.go b/web/views.go
index f8a45d3..551a74f 100644
--- a/web/views.go
+++ b/web/views.go
@@ -68,7 +68,6 @@ type RideProfileClimb struct {
TopKm float64 `json:"topKm"`
TopElevationM float64 `json:"topElevationM"`
Name string `json:"name"`
- Score float64 `json:"score"`
Category string `json:"category"`
DistanceKm float64 `json:"distanceKm"`
SlopePercent float64 `json:"slopePercent"`
@@ -269,7 +268,6 @@ func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, off
TopKm: segment.TopDistanceM() / 1000,
TopElevationM: segment.TopElevationM(),
Name: analyzedClimb.Name,
- Score: analyzedClimb.Score,
Category: analyzedClimb.Category,
DistanceKm: analyzedClimb.DistanceM / 1000,
SlopePercent: analyzedClimb.SlopePercent,
@@ -327,16 +325,16 @@ func formatElevation(meters float64) string {
return fmt.Sprintf("%.0f m", meters)
}
-func formatCotacol(score float64) string {
- return fmt.Sprintf("%.1f", score)
+func formatCotacol(cotacol float64) string {
+ return fmt.Sprintf("%.1f", cotacol)
}
-func formatCotacolPer100Km(score, distanceM float64) string {
+func formatCotacolPer100Km(cotacol, distanceM float64) string {
distanceKm := distanceM / 1000
if distanceKm <= 0 {
return "-"
}
- return fmt.Sprintf("%.1f", score*100/distanceKm)
+ return fmt.Sprintf("%.1f", cotacol*100/distanceKm)
}
func formatRouteIndex(index int) string {