diff --git a/gpx/src/gpx.ts b/gpx/src/gpx.ts index 1dc1ca3b..90cdcd17 100644 --- a/gpx/src/gpx.ts +++ b/gpx/src/gpx.ts @@ -349,7 +349,7 @@ export class TrackSegment extends GPXTreeLeaf { computeSlope(): number[] { const points = this.trkpt; - return distanceWindowSmoothingWithDistanceAccumulator(points, 250, (accumulated, start, end) => accumulated > 1e-3 ? 100 * (points[end].ele - points[start].ele) / accumulated : 0); + return distanceWindowSmoothingWithDistanceAccumulator(points, 50, (accumulated, start, end) => 100 * (points[end].ele - points[start].ele) / accumulated); } reverse(originalNextTimestamp: Date | undefined, newPreviousTimestamp: Date | undefined): void { @@ -442,6 +442,10 @@ export class TrackPoint { getPower(): number { return this.extensions && this.extensions["gpxpx:PowerExtension"] && this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] ? this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] : undefined; } + + getSurface(): string { + return this.extensions && this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface ? this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface : undefined; + } }; export class Waypoint { diff --git a/website/src/lib/assets/surfaces.ts b/website/src/lib/assets/surfaces.ts new file mode 100644 index 00000000..efbfc249 --- /dev/null +++ b/website/src/lib/assets/surfaces.ts @@ -0,0 +1,31 @@ +export const surfaceColors: { [key: string]: string } = { + 'missing': '#d1d1d1', + 'paved': '#8c8c8c', + 'unpaved': '#6b443a', + 'asphalt': '#8c8c8c', + 'concrete': '#8c8c8c', + 'chipseal': '#8c8c8c', + 'cobblestone': '#ffd991', + 'unhewn_cobblestone': '#ffd991', + 'paving_stones': '#8c8c8c', + 'stepping_stones': '#c7b2db', + 'sett': '#ffd991', + 'metal': '#8c8c8c', + 'wood': '#6b443a', + 'compacted': '#ffffa8', + 'fine_gravel': '#ffffa8', + 'gravel': '#ffffa8', + 'pebblestone': '#ffffa8', + 'rock': '#ffd991', + 'dirt': '#ffffa8', + 'ground': '#6b443a', + 'earth': '#6b443a', + 'snow': '#bdfffc', + 'ice': '#bdfffc', + 'salt': '#b6c0f2', + 'mud': '#6b443a', + 'sand': '#ffffc4', + 'woodchips': '#6b443a', + 'grass': '#61b55c', + 'grass_paver': '#61b55c' +} \ No newline at end of file diff --git a/website/src/lib/components/ElevationProfile.svelte b/website/src/lib/components/ElevationProfile.svelte index 177a067e..82fab3d8 100644 --- a/website/src/lib/components/ElevationProfile.svelte +++ b/website/src/lib/components/ElevationProfile.svelte @@ -18,6 +18,7 @@ Zap } from 'lucide-svelte'; import { GPXFiles } from 'gpx'; + import { surfaceColors } from '$lib/assets/surfaces'; let canvas: HTMLCanvasElement; let chart: Chart; @@ -53,7 +54,8 @@ datasets: { line: { pointRadius: 0, - tension: 0.4 + tension: 0.4, + borderWidth: 2 } }, interaction: { @@ -139,11 +141,14 @@ data: trackPointsAndStatistics.points.map((point, index) => { return { x: trackPointsAndStatistics.statistics.distance[index], - y: point.ele ? point.ele : 0 + y: point.ele ? point.ele : 0, + slope: trackPointsAndStatistics.statistics.slope[index], + surface: point.getSurface() }; }), normalized: true, - fill: true + fill: true, + order: 1 }; chart.data.datasets[1] = { label: datasets.speed.label, @@ -210,7 +215,62 @@ chart.update(); } - $: console.log(elevationFill); + let slopeColors = [ + '#046307', + '#028306', + '#2AA12E', + '#53BF56', + '#7BDD7E', + '#A4FBA6', + '#edf0bd', + '#ffcc99', + '#F29898', + '#E07575', + '#CF5352', + '#BE312F', + '#AD0F0C' + ]; + + function slopeFillCallback(context) { + let slope = context.p0.raw.slope; + if (slope <= 1 && slope >= -1) return slopeColors[6]; + else if (slope > 0) { + if (slope <= 3) return slopeColors[7]; + else if (slope <= 5) return slopeColors[8]; + else if (slope <= 7) return slopeColors[9]; + else if (slope <= 10) return slopeColors[10]; + else if (slope <= 15) return slopeColors[11]; + else return slopeColors[12]; + } else { + if (slope >= -3) return slopeColors[5]; + else if (slope >= -5) return slopeColors[4]; + else if (slope >= -7) return slopeColors[3]; + else if (slope >= -10) return slopeColors[2]; + else if (slope >= -15) return slopeColors[1]; + else return slopeColors[0]; + } + } + + function surfaceFillCallback(context) { + let surface = context.p0.raw.surface; + return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing; + } + + $: if (chart) { + if (elevationFill === 'slope') { + chart.data.datasets[0]['segment'] = { + backgroundColor: slopeFillCallback + }; + } else if (elevationFill === 'surface') { + chart.data.datasets[0]['segment'] = { + backgroundColor: surfaceFillCallback + }; + } else { + chart.data.datasets[0]['segment'] = {}; + } + chart.update(); + } + $: if (additionalDatasets && chart) { let includeSpeed = additionalDatasets.includes('speed'); let includeHeartRate = additionalDatasets.includes('hr'); diff --git a/website/src/lib/components/GPXData.svelte b/website/src/lib/components/GPXData.svelte index 419719bb..b45c34c0 100644 --- a/website/src/lib/components/GPXData.svelte +++ b/website/src/lib/components/GPXData.svelte @@ -28,7 +28,7 @@ } - +