diff --git a/gpx/src/gpx.ts b/gpx/src/gpx.ts index f9276b47..b37ac0ef 100644 --- a/gpx/src/gpx.ts +++ b/gpx/src/gpx.ts @@ -15,6 +15,7 @@ abstract class GPXTreeElement> { abstract getChildren(): T[]; abstract computeStatistics(): GPXStatistics; + abstract refreshStatistics(): void; abstract append(points: TrackPoint[]): void; abstract reverse(originalNextTimestamp?: Date, newPreviousTimestamp?: Date): void; @@ -34,15 +35,19 @@ abstract class GPXTreeNode> extends GPXTreeElement } computeStatistics(): GPXStatistics { - let statistics = new GPXStatistics(); - for (let child of this.getChildren()) { - statistics.mergeWith(child.computeStatistics()); + child.computeStatistics(); } + this.refreshStatistics(); + return this.statistics; + } - this.statistics = statistics; - - return statistics; + refreshStatistics(): void { + this.statistics = new GPXStatistics(); + for (let child of this.getChildren()) { + child.refreshStatistics(); + this.statistics.mergeWith(child.statistics); + } } append(points: TrackPoint[]): void { @@ -53,6 +58,8 @@ abstract class GPXTreeNode> extends GPXTreeElement } children[children.length - 1].append(points); + + this.refreshStatistics(); } reverse(originalNextTimestamp?: Date, newPreviousTimestamp?: Date): void { @@ -73,6 +80,8 @@ abstract class GPXTreeNode> extends GPXTreeElement originalNextTimestamp = originalStartTimestamp; newPreviousTimestamp = children[i].getEndTimestamp(); } + + this.refreshStatistics(); } getStartTimestamp(): Date { @@ -352,6 +361,9 @@ export class TrackSegment extends GPXTreeLeaf { return statistics; } + // Do nothing, recompute statistics after modifying the segment only + refreshStatistics(): void { } + computeSmoothedElevation(): number[] { const points = this.trkpt; @@ -373,7 +385,7 @@ export class TrackSegment extends GPXTreeLeaf { append(points: TrackPoint[]): void { this.trkpt = this.trkpt.concat(points); - //this.computeStatistics(); + this.computeStatistics(); } reverse(originalNextTimestamp: Date | undefined, newPreviousTimestamp: Date | undefined): void { @@ -393,6 +405,7 @@ export class TrackSegment extends GPXTreeLeaf { } else { this.trkpt.reverse(); } + this.computeStatistics(); } getStartTimestamp(): Date { diff --git a/website/src/lib/components/ElevationProfile.svelte b/website/src/lib/components/ElevationProfile.svelte index a108871b..2f2cb6f7 100644 --- a/website/src/lib/components/ElevationProfile.svelte +++ b/website/src/lib/components/ElevationProfile.svelte @@ -230,7 +230,7 @@ }); $: if (chart && $settings) { - let gpxFiles = new GPXFiles(Array.from($selectedFiles).map((file) => get(file))); + let gpxFiles = new GPXFiles(Array.from($selectedFiles)); gpxFiles.files.sort(function (a, b) { return get(fileOrder).indexOf(a) - get(fileOrder).indexOf(b); }); diff --git a/website/src/lib/components/FileList.svelte b/website/src/lib/components/FileList.svelte index 3aedcb51..b5d5d5ca 100644 --- a/website/src/lib/components/FileList.svelte +++ b/website/src/lib/components/FileList.svelte @@ -1,5 +1,5 @@ diff --git a/website/src/lib/components/GPXMapLayer.svelte b/website/src/lib/components/GPXMapLayer.svelte index 929d2942..ca76f7c7 100644 --- a/website/src/lib/components/GPXMapLayer.svelte +++ b/website/src/lib/components/GPXMapLayer.svelte @@ -59,9 +59,9 @@ function selectOnClick(e: any) { if (e.originalEvent.shiftKey) { - get(selectFiles).addSelect(file); + get(selectFiles).addSelect(get(file)); } else { - get(selectFiles).select(file); + get(selectFiles).select(get(file)); } } @@ -125,16 +125,19 @@ } } - $: if ($map) { - $map.on('style.load', addGPXLayer); - } - - $: if ($selectedFiles.has(file)) { + $: if ($selectedFiles.has(get(file))) { if ($map) { $map.moveLayer(layerId); } } + $: if ($map) { + let source = $map.getSource(layerId); + if (source) { + source.setData(extendGeoJSON($file.toGeoJSON())); + } + } + onMount(() => { addGPXLayer(); if ($map) { @@ -178,16 +181,11 @@ } ); } + + $map.on('style.load', addGPXLayer); } }); - $: if ($map) { - let source = $map.getSource(layerId); - if (source) { - source.setData(extendGeoJSON($file.toGeoJSON())); - } - } - onDestroy(() => { if ($map) { $map.off('click', layerId, selectOnClick); diff --git a/website/src/lib/components/toolbar/routing/Routing.svelte b/website/src/lib/components/toolbar/routing/Routing.svelte index 4799e9ef..77cee8f6 100644 --- a/website/src/lib/components/toolbar/routing/Routing.svelte +++ b/website/src/lib/components/toolbar/routing/Routing.svelte @@ -7,8 +7,7 @@ import * as Alert from '$lib/components/ui/alert'; import { CircleHelp } from 'lucide-svelte'; - import { map, selectedFiles } from '$lib/stores'; - import { get, type Writable } from 'svelte/store'; + import { map, selectedFiles, getFileStore, applyToFile } from '$lib/stores'; import { AnchorPointHierarchy, getMarker, route } from './routing'; import { onDestroy } from 'svelte'; import mapboxgl from 'mapbox-gl'; @@ -36,7 +35,7 @@ let anchorPointHierarchy: AnchorPointHierarchy | null = null; let markers: mapboxgl.Marker[] = []; - let file: Writable | null = null; + let file: GPXFile | null = null; let kdbush: KDBush | null = null; function toggleMarkersForZoomLevelAndBounds() { @@ -65,11 +64,7 @@ privateRoads, routing ); - console.log(response); - file.update((file) => { - file.append(response); - return file; - }); + applyToFile(file, (f) => f.append(response)); } } @@ -111,7 +106,7 @@ $map.off('move', toggleMarkersForZoomLevelAndBounds); $map.off('click', extendFile); if (file) { - $map.off('mouseover', get(file).layerId, showInsertableMarker); + $map.off('mouseover', file.layerId, showInsertableMarker); } if (insertableMarker) { insertableMarker.remove(); @@ -127,7 +122,7 @@ // record time let start = performance.now(); - anchorPointHierarchy = AnchorPointHierarchy.create(get(file)); + anchorPointHierarchy = AnchorPointHierarchy.create(file); // record time let end = performance.now(); console.log('Time to create anchor points: ' + (end - start) + 'ms'); @@ -138,9 +133,9 @@ $map.on('zoom', toggleMarkersForZoomLevelAndBounds); $map.on('move', toggleMarkersForZoomLevelAndBounds); $map.on('click', extendFile); - $map.on('mouseover', get(file).layerId, showInsertableMarker); + $map.on('mouseover', file.layerId, showInsertableMarker); - let points = get(file).getTrackPoints(); + let points = file.getTrackPoints(); start = performance.now(); kdbush = new KDBush(points.length); diff --git a/website/src/lib/stores.ts b/website/src/lib/stores.ts index 8e1936c4..0a9c6fd0 100644 --- a/website/src/lib/stores.ts +++ b/website/src/lib/stores.ts @@ -5,15 +5,32 @@ import { GPXFile, buildGPX, parseGPX } from 'gpx'; export const map = writable(null); export const files = writable[]>([]); -export const fileOrder = writable[]>([]); -export const selectedFiles = writable>>(new Set()); -export const selectFiles = writable<{ [key: string]: (file?: Writable) => void }>({}); +export const fileOrder = writable([]); +export const selectedFiles = writable>(new Set()); +export const selectFiles = writable<{ [key: string]: (file?: GPXFile) => void }>({}); export const settings = writable<{ [key: string]: any }>({ distanceUnits: 'metric', velocityUnits: 'speed', temperatureUnits: 'celsius', }); +export function getFileStore(file: GPXFile): Writable { + return get(files).find(store => get(store) === file) ?? addFile(file); +} + +export function getFileIndex(file: GPXFile): number { + return get(files).findIndex(store => get(store) === file); +} + +export function applyToFile(file: GPXFile, callback: (file: GPXFile) => void) { + let store = getFileStore(file); + store.update($file => { + callback($file) + return $file; + }); + selectedFiles.update($selected => $selected); +} + export function addFile(file: GPXFile): Writable { let fileStore = writable(file); files.update($files => { @@ -41,7 +58,7 @@ export async function loadFiles(list: FileList) { for (let i = 0; i < list.length; i++) { let file = await loadFile(list[i]); if (i == 0 && file) { - get(selectFiles).select(file); + get(selectFiles).select(get(file)); } } } @@ -68,7 +85,7 @@ export async function loadFile(file: File) { export function duplicateSelectedFiles() { let selected: GPXFile[] = []; - get(selectedFiles).forEach(file => selected.push(get(file))); + get(selectedFiles).forEach(file => selected.push(file)); selected.forEach(file => duplicateFile(file)); } @@ -81,7 +98,7 @@ export function removeSelectedFiles() { files.update($files => { let index = 0; while (index < $files.length) { - if (get(selectedFiles).has($files[index])) { + if (get(selectedFiles).has(get($files[index]))) { $files.splice(index, 1); } else { index++; @@ -107,7 +124,7 @@ export function removeAllFiles() { } export function exportSelectedFiles() { - get(selectedFiles).forEach(file => exportFile(get(file))); + get(selectedFiles).forEach(file => exportFile(file)); } export async function exportAllFiles() { @@ -128,15 +145,5 @@ export function exportFile(file: GPXFile) { } export function reverseSelectedFiles() { - files.update($files => { - $files.forEach(file => { - if (get(selectedFiles).has(file)) { - file.update($file => { - $file.reverse(); - return $file; - }); - } - }); - return $files; - }); + get(selectedFiles).forEach(file => applyToFile(file, file => file.reverse())); } \ No newline at end of file