Skip to content

Commit

Permalink
Code cleanup, add clickable routes
Browse files Browse the repository at this point in the history
  • Loading branch information
Zenmaster28 committed Jul 30, 2024
1 parent eadc0f2 commit daf0381
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 56 deletions.
25 changes: 15 additions & 10 deletions pages/css/elevation-segments.css
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ th:last-child, td:last-child {
padding: 0.5em 0.8em;
overflow: auto;
}
#content {
display: grid;
.segmentContent {
display: grid !important;
grid-template-columns: 1fr 1fr;
grid-gap: 20px;
text-align: left;
font-variant: tabular-nums;
font-size: calc(var(--font-scale) * 1em);
}
#content > .elevation-profile {
.segmentContent > .elevation-profile {
--profile-height: 0.20;
flex: 0 0 auto;
position: absolute;
Expand All @@ -140,15 +142,15 @@ th:last-child, td:last-child {
pointer-events: none;
transform: translateZ(0);
height: calc(var(--profile-height) * 100%);
width: 50%;
width: 50% !important;
overflow: hidden;
}
#content > .elevation-profile svg > g {
.segmentContent > .elevation-profile svg > g {
pointer-events: all;
}
#content > .map {
.segmentContent > .map {
flex: 1 1 0;
width: 101%;
width: 101% !important;
height: 100%;
}

Expand All @@ -162,14 +164,17 @@ th:last-child, td:last-child {
text-align: left;
}
#resultsTable td:first-child, #resultsTable th:first-child {
width: 30%;
width: 25%;
}

#resultsTable td:nth-child(2), #resultsTable th:nth-child(2),
#resultsTable td:nth-child(3), #resultsTable th:nth-child(3) {
width: 20%;
width: 15%;
}

#resultsTable td:last-child, #resultsTable th:last-child {
width: 30%;
width: 45%;
}
#stats {
overflow-y: auto;
}
4 changes: 4 additions & 0 deletions pages/segment-data-settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
<key data-added="2023-11-01">Show max elevation:</key>
<input type="checkbox" name="showElevationMaxLine" checked/>
</label>
<label>
<key>Show recent results:</key>
<input type="checkbox" name="showResults">
</label>
<label>
<key>Sort segment times by:</key>
<select name="sortBy">
Expand Down
167 changes: 121 additions & 46 deletions pages/src/segment-data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ common.settingsStore.setDefault({
showMap: true,
showAllArches: false,
sortBy: "time",
sortOrder: "asc"
sortOrder: "asc",
showResults: true
});

doc.style.setProperty('--font-scale', common.settingsStore.get('fontScale') || 1);
const settings = common.settingsStore.get();
const url = new URL(location);
const courseSelect = document.querySelector('#titlebar select[name="course"]');
Expand All @@ -51,8 +52,8 @@ let inGame;
let zwiftMap;
let elProfile;
let courseId = Number(url.searchParams.get('course')) || 6;
let urlRoute = url.searchParams.get('route')
let routeId = urlRoute ? BigInt(urlRoute) : undefined;
let urlSegment = url.searchParams.get('segment')
let segmentId = urlSegment ? BigInt(urlSegment) : undefined;
let currentRoute;

function qualityScale(raw) {
Expand Down Expand Up @@ -273,11 +274,11 @@ function centerMap(positions, options) {
const _routeHighlights = [];
async function applySegment() {
//console.log("applying segment")
//console.log("zoomCenter is " + zoomCenter)
if (routeId != null) {
url.searchParams.set('route', routeId);

if (segmentId != null) {
url.searchParams.set('segment', segmentId);
} else {
url.searchParams.delete('route');
url.searchParams.delete('segment');
}
history.replaceState({}, '', url);
while (_routeHighlights.length) {
Expand All @@ -291,77 +292,151 @@ async function applySegment() {
continue;
}
segmentSelect.insertAdjacentHTML('beforeend', `
<option ${x.id == routeId ? 'selected' : ''}
<option ${x.id == segmentId ? 'selected' : ''}
value="${x.id}">${common.stripHTML(x.name)} (${common.stripHTML((x.distance).toFixed(0))}m) </option>`);
}
if (routeId != null) {
const route = await zen.getSegmentPath(routeId);
if (segmentId != null) {
const segment = await zen.getSegmentPath(segmentId);
let path;
//debugger
if (zwiftMap.overrideDistance > 0) {
let idx = common.binarySearchClosest(route.distances, zwiftMap.overrideDistance)
path = route.curvePath;
path = segment.curvePath;
path.nodes = path.nodes.slice(0, idx + 1)
} else {
path = route.curvePath;
path = segment.curvePath;
}
//debugger
_routeHighlights.push(
zwiftMap.addHighlightPath(path, `route-1-${route.id}`, {width: 5, color: '#0004'}),
zwiftMap.addHighlightPath(path, `route-2-${route.id}`, {width: 1.2, color: 'black'}),
zwiftMap.addHighlightPath(path, `route-3-${route.id}`, {width: 0.5, color: 'gold'}),
zwiftMap.addHighlightPath(path, `route-1-${segment.id}`, {width: 5, color: '#0004'}),
zwiftMap.addHighlightPath(path, `route-2-${segment.id}`, {width: 1.2, color: 'black'}),
zwiftMap.addHighlightPath(path, `route-3-${segment.id}`, {width: 0.5, color: 'gold'}),
);
let padding = 0.2;
if (route.distance < 1000) {
if (segment.distance < 1000) {
padding = 0.8
} else if (route.distance >= 1000 && route.distance < 2500) {
} else if (segment.distance >= 1000 && segment.distance < 2500) {
padding = 0.6
}
centerMap(route.curvePath.flatten(1/3), {padding: padding});
centerMap(segment.curvePath.flatten(1/3), {padding: padding});
//debugger
await elProfile.setSegment(route)
await elProfile.setSegment(segment)
const segmentInfoDiv = document.getElementById("segmentInfo");
const athleteTimesDiv = document.getElementById("athleteTimes")
segmentInfoDiv.innerHTML = "Segment: "
segmentInfoDiv.innerHTML += route.name + "<br>Distance: " + route.distance.toFixed(0) + "m"
let segmentBests = await getSegmentBests(route.id)
if (settings.sortBy == "date") {
segmentBests.sort((a,b) => {
if (settings.sortOrder == "desc") {
return b.ts - a.ts
} else {
return a.ts - b.ts
athleteTimesDiv.innerHTML = ""
segmentInfoDiv.innerHTML = `<h1 style="font-size:calc(var(--font-scale) * 1.5em);">${segment.name} (${segment.distance.toFixed(0)}m)</h1><hr>`
//segmentInfoDiv.innerHTML += segment.name + "<br>Distance: " + segment.distance.toFixed(0) + "m<hr>"
if (settings.showResults) {
let segmentBests = await getSegmentBests(segment.id)
if (settings.sortBy == "date") {
segmentBests.sort((a,b) => {
if (settings.sortOrder == "desc") {
return b.ts - a.ts
} else {
return a.ts - b.ts
}
})
} else if (settings.sortOrder == "desc") {
segmentBests.sort((a,b) => {
return b.elapsed - a.elapsed
})
}
if (segmentBests.length > 0) {
let tableOutput = "<table id='resultsTable'><tr><th><b>Time</th><th><b>Power (w)</th><th><b>Weight (kg)</th><th><b>Date</th></tr>"
for (let r of segmentBests) {
tableOutput += `<tr><td>${zen.formatTime(r.elapsed * 1000)}</td><td>${r.avgPower}</td><td>${r.weight}</td><td>${zen.formatTs(r.ts)}</td></tr>`
}
})
} else if (settings.sortOrder == "desc") {
segmentBests.sort((a,b) => {
return b.elapsed - a.elapsed
})
athleteTimesDiv.innerHTML = tableOutput
} else {
athleteTimesDiv.innerHTML = "No recent results found"
}
}
if (segmentBests.length > 0) {
let tableOutput = "<table id='resultsTable'><tr><th>Time</th><th>Power (w)</th><th>weight (kg)</th><th>Date</th></tr>"
for (let r of segmentBests) {
tableOutput += `<tr><td>${zen.formatTime(r.elapsed * 1000)}</td><td>${r.avgPower}</td><td>${r.weight}</td><td>${zen.formatTs(r.ts)}</td></tr>`
let segmentRoutes = await getSegmentRoutes(segment, courseId)
athleteTimesDiv.innerHTML += "<hr><b>Routes that pass through this segment (click on the route to view details)</b><br>"
//console.log(segmentRoutes)
if (segmentRoutes.length > 0) {
segmentRoutes.sort((a,b) => {
if (a.name < b.name) {
return -1
}
if (a.name > b.name) {
return 1
}
return 0
})
for (let rte of segmentRoutes) {
athleteTimesDiv.innerHTML += `<a href=route-preview-v2.html?course=${rte.courseId}&route=${rte.id}
target=routepreview>${rte.name} (${(rte.distanceInMeters / 1000).toFixed(1)}km / ${rte.ascentInMeters.toFixed(0)}m)</a><br>`
}
athleteTimesDiv.innerHTML = tableOutput
} else {
athleteTimesDiv.innerHTML = "No recent results found"
}
//debugger
} else {
zwiftMap.setVerticalOffset(0);
zwiftMap.setDragOffset([0, 0]);
zwiftMap.setZoom(0.3);
if (elProfile) {
elProfile.clear();
}
document.getElementById("segmentInfo").innerHTML = "<br><br><br><br><center>Choose a segment from the dropdown list."
}
}

async function getSegmentBests(segmentId) {
async function getSegmentRoutes(segment, courseId) {
const routeList = await common.getRouteList(courseId)
let zwiftSegmentsRequireStartEnd = await fetch("data/segRequireStartEnd.json").then((response) => response.json());
let requireStartEnd = zwiftSegmentsRequireStartEnd.includes(segment.id)
//debugger
let filteredRoutes
if (requireStartEnd) {
if (segment.reverse) {
filteredRoutes = routeList.filter(route =>
route.manifest.some(roadSeg => roadSeg.roadId === segment.roadId &&
roadSeg.reverse == segment.reverse &&
roadSeg.end >= segment.roadStart &&
roadSeg.start <= segment.roadFinish
)
);
} else {
filteredRoutes = routeList.filter(route =>
route.manifest.some(roadSeg => roadSeg.roadId === segment.roadId &&
roadSeg.start <= segment.roadStart &&
roadSeg.end >= segment.roadFinish
)
);
}
} else {
if (segment.reverse) {
filteredRoutes = routeList.filter(route =>
route.manifest.some(roadSeg => roadSeg.roadId === segment.roadId &&
roadSeg.reverse == segment.reverse &&
((roadSeg.end >= segment.roadStart &&
roadSeg.start <= segment.roadStart) ||
(roadSeg.start <= segment.roadFinish &&
roadSeg.end >= segment.roadFinish
))
)
);
} else {
filteredRoutes = routeList.filter(route =>
route.manifest.some(roadSeg => roadSeg.roadId === segment.roadId &&
!roadSeg.reverse &&
((roadSeg.start <= segment.roadStart &&
roadSeg.end >= segment.roadStart) ||
(roadSeg.start <= segment.roadFinish &&
roadSeg.end >= segment.roadFinish
))
)
);
}
}
//console.log(filteredRoutes);
return filteredRoutes;
}


async function getSegmentBests(id) {
let athleteId = await common.rpc.getAthlete("self")
athleteId = athleteId.id
let segmentBests = await common.rpc.getSegmentResults(segmentId, {athleteId: athleteId, from: Date.now() - 86400000 * 90,})
let segmentBests = await common.rpc.getSegmentResults(id, {athleteId: athleteId, from: Date.now() - 86400000 * 90,})
if (segmentBests) {
return segmentBests;
}
Expand Down Expand Up @@ -406,7 +481,7 @@ export async function main() {
common.initInteractionListeners();
common.setBackground(settings);
segmentSelect.addEventListener('change', async ev => {
routeId = BigInt(segmentSelect.value);
segmentId = BigInt(segmentSelect.value);
await applySegment();
});
courseSelect.addEventListener('change', async ev => {
Expand All @@ -416,7 +491,7 @@ export async function main() {
return;
}
courseId = id;
routeId = undefined;
segmentId = undefined;
[worldList, segmentsList] = await getCourseSegments(courseId)
elProfile.clear();
await applyCourse();
Expand Down

0 comments on commit daf0381

Please sign in to comment.