From ccc26f79e70f0cb3adcc3a3c40a781cc2e557bd2 Mon Sep 17 00:00:00 2001 From: vcoppe Date: Sat, 27 Apr 2024 12:18:40 +0200 Subject: [PATCH] create new file --- gpx/src/gpx.ts | 48 ++++++++++++------- gpx/src/types.ts | 2 +- website/src/lib/components/Menu.svelte | 10 ++-- .../lib/components/routing/RoutingControls.ts | 7 +++ .../src/lib/components/routing/Simplify.ts | 8 ++++ website/src/lib/stores.ts | 11 +++++ website/src/locales/en.json | 1 + 7 files changed, 67 insertions(+), 20 deletions(-) diff --git a/gpx/src/gpx.ts b/gpx/src/gpx.ts index c44cb2d1..2a9e8349 100644 --- a/gpx/src/gpx.ts +++ b/gpx/src/gpx.ts @@ -164,12 +164,19 @@ export class GPXFile extends GPXTreeNode{ wpt: Waypoint[]; trk: Track[]; - constructor(gpx: GPXFileType | GPXFile) { + constructor(gpx?: GPXFileType | GPXFile) { super(); - this.attributes = cloneJSON(gpx.attributes); - this.metadata = cloneJSON(gpx.metadata); - this.wpt = gpx.wpt ? gpx.wpt.map((waypoint) => new Waypoint(waypoint)) : []; - this.trk = gpx.trk ? gpx.trk.map((track) => new Track(track)) : []; + if (gpx) { + this.attributes = cloneJSON(gpx.attributes); + this.metadata = cloneJSON(gpx.metadata); + this.wpt = gpx.wpt ? gpx.wpt.map((waypoint) => new Waypoint(waypoint)) : []; + this.trk = gpx.trk ? gpx.trk.map((track) => new Track(track)) : []; + } else { + this.attributes = {}; + this.metadata = {}; + this.wpt = []; + this.trk = [new Track()]; + } } getChildren(): Track[] { @@ -208,16 +215,20 @@ export class Track extends GPXTreeNode { trkseg: TrackSegment[]; extensions?: TrackExtensions; - constructor(track: TrackType | Track) { + constructor(track?: TrackType | Track) { super(); - this.name = track.name; - this.cmt = track.cmt; - this.desc = track.desc; - this.src = track.src; - this.link = cloneJSON(track.link); - this.type = track.type; - this.trkseg = track.trkseg ? track.trkseg.map((seg) => new TrackSegment(seg)) : []; - this.extensions = cloneJSON(track.extensions); + if (track) { + this.name = track.name; + this.cmt = track.cmt; + this.desc = track.desc; + this.src = track.src; + this.link = cloneJSON(track.link); + this.type = track.type; + this.trkseg = track.trkseg ? track.trkseg.map((seg) => new TrackSegment(seg)) : []; + this.extensions = cloneJSON(track.extensions); + } else { + this.trkseg = [new TrackSegment()]; + } } getChildren(): TrackSegment[] { @@ -266,9 +277,14 @@ export class TrackSegment extends GPXTreeLeaf { trkptStatistics: TrackPointStatistics; statistics: GPXStatistics; - constructor(segment: TrackSegmentType | TrackSegment) { + constructor(segment?: TrackSegmentType | TrackSegment) { super(); - this.trkpt = segment.trkpt.map((point) => new TrackPoint(point)); + if (segment) { + this.trkpt = segment.trkpt.map((point) => new TrackPoint(point)); + } else { + this.trkpt = []; + } + this._computeStatistics(); } diff --git a/gpx/src/types.ts b/gpx/src/types.ts index 0b7cf642..05033174 100644 --- a/gpx/src/types.ts +++ b/gpx/src/types.ts @@ -6,7 +6,7 @@ export type GPXFileType = { }; export type GPXFileAttributes = { - creator: string; + creator?: string; [key: string]: string; }; diff --git a/website/src/lib/components/Menu.svelte b/website/src/lib/components/Menu.svelte index 7a6e8d95..e48c2bd5 100644 --- a/website/src/lib/components/Menu.svelte +++ b/website/src/lib/components/Menu.svelte @@ -14,7 +14,8 @@ removeSelectedFiles, triggerFileInput, selectFiles, - settings + settings, + createFile } from '$lib/stores'; import { mode, resetMode, setMode } from 'mode-watcher'; @@ -51,7 +52,7 @@ {$_('menu.file')} - + {$_('menu.new')} ⌘N @@ -183,7 +184,10 @@ { e.stopImmediatePropagation(); - if (e.key === 'o' && (e.metaKey || e.ctrlKey)) { + if (e.key === 'n' && (e.metaKey || e.ctrlKey)) { + createFile(); + e.preventDefault(); + } else if (e.key === 'o' && (e.metaKey || e.ctrlKey)) { triggerFileInput(); e.preventDefault(); } else if (e.key === 'd' && (e.metaKey || e.ctrlKey)) { diff --git a/website/src/lib/components/routing/RoutingControls.ts b/website/src/lib/components/routing/RoutingControls.ts index 7f717dec..44eea234 100644 --- a/website/src/lib/components/routing/RoutingControls.ts +++ b/website/src/lib/components/routing/RoutingControls.ts @@ -339,6 +339,13 @@ export class RoutingControls { this.createMarker(newAnchor); segment._data.anchors.push(newAnchor); + if (!lastAnchor) { + applyToFileElement(this.file, segment, (segment) => { + segment.replace(0, 0, [newPoint]); + }, true); + return; + } + let success = await this.routeBetweenAnchors([lastAnchor, newAnchor], [lastAnchor.point.getCoordinates(), newAnchor.point.getCoordinates()]); if (!success) { // Route failed, remove the anchor diff --git a/website/src/lib/components/routing/Simplify.ts b/website/src/lib/components/routing/Simplify.ts index 16342a2a..79e1babd 100644 --- a/website/src/lib/components/routing/Simplify.ts +++ b/website/src/lib/components/routing/Simplify.ts @@ -25,6 +25,14 @@ export function computeAnchorPoints(segment: TrackSegment) { } export function ramerDouglasPeucker(points: TrackPoint[], epsilon: number = 50, start: number = 0, end: number = points.length - 1): SimplifiedTrackPoint[] { + if (points.length == 0) { + return []; + } else if (points.length == 1) { + return [{ + point: points[0] + }]; + } + let simplified = [{ point: points[start] }]; diff --git a/website/src/lib/stores.ts b/website/src/lib/stores.ts index a98e675c..462b6f3d 100644 --- a/website/src/lib/stores.ts +++ b/website/src/lib/stores.ts @@ -2,6 +2,8 @@ import { writable, get, type Writable } from 'svelte/store'; import mapboxgl from 'mapbox-gl'; import { GPXFile, buildGPX, parseGPX, type AnyGPXTreeElement } from 'gpx'; +import { tick } from 'svelte'; +import { _ } from 'svelte-i18n'; export const map = writable(null); export const files = writable[]>([]); @@ -72,6 +74,15 @@ export function addFile(file: GPXFile): Writable { return fileStore; } +export function createFile(): Writable { + let file = new GPXFile(); + file.metadata.name = get(_)("menu.new_filename"); + let fileStore = addFile(file); + tick().then(() => get(selectFiles).select(file)); + currentTool.set(Tool.ROUTING); + return fileStore; +} + export function triggerFileInput() { const input = document.createElement('input'); input.type = 'file'; diff --git a/website/src/locales/en.json b/website/src/locales/en.json index fe15047d..83dfba77 100644 --- a/website/src/locales/en.json +++ b/website/src/locales/en.json @@ -2,6 +2,7 @@ "menu": { "file": "File", "new": "New", + "new_filename": "new", "load_desktop": "Load from desktop...", "load_drive": "Load from Google Drive...", "duplicate": "Duplicate",