summaryrefslogtreecommitdiff
path: root/web/views.go
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-16 10:31:32 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-16 10:31:32 +0200
commit0c3507139795c3117bcdf82ca4b444e934bd3c74 (patch)
tree626f62c7dc15ded26bfeedbfa32a6638c07c3dfa /web/views.go
parentc720b572573774504cbbeda5ac1b5da2d1afeff6 (diff)
feat(web): improve ride detail climb profiles
Diffstat (limited to 'web/views.go')
-rw-r--r--web/views.go57
1 files changed, 42 insertions, 15 deletions
diff --git a/web/views.go b/web/views.go
index 79356d2..6c96576 100644
--- a/web/views.go
+++ b/web/views.go
@@ -29,9 +29,11 @@ type RideDetailView struct {
}
type RideProfile struct {
- Points []RideProfilePoint `json:"points"`
- Climbs []RideProfileClimb `json:"climbs"`
- Crossings []RideProfileCrossing `json:"crossings"`
+ Points []RideProfilePoint `json:"points"`
+ Climbs []RideProfileClimb `json:"climbs"`
+ OfficialClimbs []RideProfileClimb `json:"-"`
+ UnmatchedClimbs []RideProfileClimb `json:"-"`
+ Crossings []RideProfileCrossing `json:"crossings"`
}
type RideProfilePoint struct {
@@ -42,6 +44,7 @@ type RideProfilePoint struct {
}
type RideProfileClimb struct {
+ Index int `json:"-"`
StartKm float64 `json:"startKm"`
EndKm float64 `json:"endKm"`
TopKm float64 `json:"topKm"`
@@ -225,9 +228,11 @@ func buildRideDetailView(item rides.Ride, parsed ride.Ride, passes []mountain_pa
func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, officialClimbs []official_climb.OfficialClimb, matchPolicy official_climb.MatchPolicy) RideProfile {
profile := RideProfile{
- Points: make([]RideProfilePoint, parsed.Len()),
- Climbs: make([]RideProfileClimb, 0),
- Crossings: make([]RideProfileCrossing, 0),
+ Points: make([]RideProfilePoint, parsed.Len()),
+ Climbs: make([]RideProfileClimb, 0),
+ OfficialClimbs: make([]RideProfileClimb, 0),
+ UnmatchedClimbs: make([]RideProfileClimb, 0),
+ Crossings: make([]RideProfileCrossing, 0),
}
for i := 0; i < parsed.Len(); i++ {
coordinate := parsed.Coord(i)
@@ -240,12 +245,13 @@ func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, off
}
analysis := rideanalysis.Analyze(parsed, passes, officialClimbs, matchPolicy)
for _, analyzedClimb := range analysis.Climbs {
- climb := analyzedClimb.Segment
- profile.Climbs = append(profile.Climbs, RideProfileClimb{
- StartKm: climb.StartDistanceM() / 1000,
- EndKm: climb.EndDistanceM() / 1000,
- TopKm: climb.TopDistanceM() / 1000,
- TopElevationM: climb.TopElevationM(),
+ segment := analyzedClimb.Segment
+ climb := RideProfileClimb{
+ Index: len(profile.Climbs),
+ StartKm: segment.StartDistanceM() / 1000,
+ EndKm: segment.EndDistanceM() / 1000,
+ TopKm: segment.TopDistanceM() / 1000,
+ TopElevationM: segment.TopElevationM(),
Name: analyzedClimb.Name,
Score: analyzedClimb.Score,
Category: analyzedClimb.Category,
@@ -254,9 +260,15 @@ func buildRideProfile(parsed ride.Ride, passes []mountain_pass.MountainPass, off
Cotacol: analyzedClimb.Cotacol,
OfficialClimbID: analyzedClimb.OfficialClimbID,
OfficialName: analyzedClimb.OfficialName,
- StartIndex: climb.StartIndex(),
- EndIndex: climb.EndIndex(),
- })
+ StartIndex: segment.StartIndex(),
+ EndIndex: segment.EndIndex(),
+ }
+ profile.Climbs = append(profile.Climbs, climb)
+ if climb.OfficialClimbID > 0 {
+ profile.OfficialClimbs = append(profile.OfficialClimbs, climb)
+ } else {
+ profile.UnmatchedClimbs = append(profile.UnmatchedClimbs, climb)
+ }
}
for _, crossing := range analysis.Crossings {
profile.Crossings = append(profile.Crossings, RideProfileCrossing{
@@ -324,6 +336,10 @@ func formatClimbNumber(index int) string {
return fmt.Sprintf("%d", index+1)
}
+func formatClimbCount(count int) string {
+ return fmt.Sprintf("%d", count)
+}
+
func formatProfileDistance(distanceKm float64) string {
return fmt.Sprintf("%.1f km", distanceKm)
}
@@ -331,3 +347,14 @@ func formatProfileDistance(distanceKm float64) string {
func formatSlope(slopePercent float64) string {
return fmt.Sprintf("%.1f%%", slopePercent)
}
+
+func officialProfileLabel(name string) string {
+ return "Elevation profile for " + name
+}
+
+func rideDetailColumnsClass(unmatchedClimbCount int) string {
+ if unmatchedClimbCount == 0 {
+ return "ride-detail-columns ride-detail-columns-single"
+ }
+ return "ride-detail-columns"
+}