diff --git a/gpx/src/gpx.ts b/gpx/src/gpx.ts index 488dd34b..b3a80282 100644 --- a/gpx/src/gpx.ts +++ b/gpx/src/gpx.ts @@ -9,6 +9,7 @@ function cloneJSON(obj: T): T { // An abstract class that groups functions that need to be computed recursively in the GPX file hierarchy abstract class GPXTreeElement> { + statistics: GPXStatistics; abstract isLeaf(): boolean; abstract getChildren(): T[]; @@ -26,8 +27,6 @@ abstract class GPXTreeElement> { // An abstract class that can be extended to facilitate functions working similarly with Tracks and TrackSegments abstract class GPXTreeNode> extends GPXTreeElement { - statistics: GPXStatistics; - isLeaf(): boolean { return false; } @@ -86,16 +85,21 @@ abstract class GPXTreeNode> extends GPXTreeElement slope: [], }; + let current = new GPXStatistics(); for (let child of this.getChildren()) { let childData = child.getTrackPointsAndStatistics(); points = points.concat(childData.points); - statistics.distance = statistics.distance.concat(childData.statistics.distance); - statistics.time = statistics.time.concat(childData.statistics.time); + + statistics.distance = statistics.distance.concat(childData.statistics.distance.map((distance) => distance + current.distance.total)); + statistics.time = statistics.time.concat(childData.statistics.time.map((time) => time + current.time.total)); + statistics.elevation.gain = statistics.elevation.gain.concat(childData.statistics.elevation.gain.map((gain) => gain + current.elevation.gain)); + statistics.elevation.loss = statistics.elevation.loss.concat(childData.statistics.elevation.loss.map((loss) => loss + current.elevation.loss)); + statistics.speed = statistics.speed.concat(childData.statistics.speed); statistics.elevation.smoothed = statistics.elevation.smoothed.concat(childData.statistics.elevation.smoothed); - statistics.elevation.gain = statistics.elevation.gain.concat(childData.statistics.elevation.gain); - statistics.elevation.loss = statistics.elevation.loss.concat(childData.statistics.elevation.loss); statistics.slope = statistics.slope.concat(childData.statistics.slope); + + current.mergeWith(child.statistics); } return { points, statistics }; @@ -113,6 +117,26 @@ abstract class GPXTreeLeaf extends GPXTreeElement { } } +// A class that represents a set of GPX files +export class GPXFiles extends GPXTreeNode { + files: GPXFile[]; + + constructor(files: GPXFile[]) { + super(); + this.files = files; + + this.computeStatistics(); + } + + getChildren(): GPXFile[] { + return this.files; + } + + toGeoJSON(): any { + return this.getChildren().map((child) => child.toGeoJSON()); + } +} + // A class that represents a GPX file export class GPXFile extends GPXTreeNode{ attributes: GPXFileAttributes; @@ -305,6 +329,7 @@ export class TrackSegment extends GPXTreeLeaf { trkptStatistics.speed = distanceWindowSmoothingWithDistanceAccumulator(points, 200, (accumulated, start, end) => 3600 * accumulated / (points[end].time.getTime() - points[start].time.getTime())); + this.statistics = statistics; this.trkptStatistics = trkptStatistics; return statistics; diff --git a/website/src/lib/components/ElevationProfile.svelte b/website/src/lib/components/ElevationProfile.svelte index 725379c8..177a067e 100644 --- a/website/src/lib/components/ElevationProfile.svelte +++ b/website/src/lib/components/ElevationProfile.svelte @@ -5,7 +5,7 @@ import Chart from 'chart.js/auto'; - import { selectedFiles } from '$lib/stores'; + import { files, fileOrder, selectedFiles } from '$lib/stores'; import { onDestroy, onMount } from 'svelte'; import { @@ -17,6 +17,7 @@ Thermometer, Zap } from 'lucide-svelte'; + import { GPXFiles } from 'gpx'; let canvas: HTMLCanvasElement; let chart: Chart; @@ -125,86 +126,88 @@ }); }); - $: { - if ($selectedFiles.size == 1) { - $selectedFiles.forEach((file) => { - const trackPointsAndStatistics = file.getTrackPointsAndStatistics(); - chart.data.datasets[0] = { - label: 'Elevation', - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: point.ele ? point.ele : 0 - }; - }), - normalized: true, - fill: true + $: if (chart) { + let gpxFiles = new GPXFiles(Array.from($selectedFiles)); + let order = $fileOrder.length == 0 ? $files : $fileOrder; + gpxFiles.files.sort(function (a, b) { + return order.indexOf(a) - order.indexOf(b); + }); + + let trackPointsAndStatistics = gpxFiles.getTrackPointsAndStatistics(); + chart.data.datasets[0] = { + label: 'Elevation', + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: point.ele ? point.ele : 0 }; - chart.data.datasets[1] = { - label: datasets.speed.label, - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: trackPointsAndStatistics.statistics.speed[index] - }; - }), - normalized: true, - yAxisID: `y${datasets.speed.id}`, - hidden: true + }), + normalized: true, + fill: true + }; + chart.data.datasets[1] = { + label: datasets.speed.label, + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: trackPointsAndStatistics.statistics.speed[index] }; - chart.data.datasets[2] = { - label: datasets.hr.label, - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: point.getHeartRate() - }; - }), - normalized: true, - yAxisID: `y${datasets.hr.id}`, - hidden: true + }), + normalized: true, + yAxisID: `y${datasets.speed.id}`, + hidden: true + }; + chart.data.datasets[2] = { + label: datasets.hr.label, + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: point.getHeartRate() }; - chart.data.datasets[3] = { - label: datasets.cad.label, - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: point.getCadence() - }; - }), - normalized: true, - yAxisID: `y${datasets.cad.id}`, - hidden: true + }), + normalized: true, + yAxisID: `y${datasets.hr.id}`, + hidden: true + }; + chart.data.datasets[3] = { + label: datasets.cad.label, + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: point.getCadence() }; - chart.data.datasets[4] = { - label: datasets.atemp.label, - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: point.getTemperature() - }; - }), - normalized: true, - yAxisID: `y${datasets.atemp.id}`, - hidden: true + }), + normalized: true, + yAxisID: `y${datasets.cad.id}`, + hidden: true + }; + chart.data.datasets[4] = { + label: datasets.atemp.label, + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: point.getTemperature() }; - chart.data.datasets[5] = { - label: datasets.power.label, - data: trackPointsAndStatistics.points.map((point, index) => { - return { - x: trackPointsAndStatistics.statistics.distance[index], - y: point.getPower() - }; - }), - normalized: true, - yAxisID: `y${datasets.power.id}`, - hidden: true + }), + normalized: true, + yAxisID: `y${datasets.atemp.id}`, + hidden: true + }; + chart.data.datasets[5] = { + label: datasets.power.label, + data: trackPointsAndStatistics.points.map((point, index) => { + return { + x: trackPointsAndStatistics.statistics.distance[index], + y: point.getPower() }; - chart.options.scales.x['min'] = 0; - chart.options.scales.x['max'] = file.statistics.distance.total; - }); - chart.update(); - } + }), + normalized: true, + yAxisID: `y${datasets.power.id}`, + hidden: true + }; + chart.options.scales.x['min'] = 0; + chart.options.scales.x['max'] = gpxFiles.statistics.distance.total; + chart.update(); } $: console.log(elevationFill); diff --git a/website/src/lib/components/FileList.svelte b/website/src/lib/components/FileList.svelte index a1efbf44..39d737af 100644 --- a/website/src/lib/components/FileList.svelte +++ b/website/src/lib/components/FileList.svelte @@ -1,5 +1,5 @@