From de1b5f3820ad4bd5347d98884af788cc3393faef Mon Sep 17 00:00:00 2001 From: vcoppe Date: Fri, 26 Apr 2024 13:33:17 +0200 Subject: [PATCH] routing control popup progress --- gpx/src/gpx.ts | 12 ++++--- website/src/lib/components/Map.svelte | 14 ++++++++ .../src/lib/components/routing/Routing.svelte | 21 +++++++++++- .../routing/RoutingControlPopup.svelte | 22 ++++++++++++ .../lib/components/routing/RoutingControls.ts | 34 ++++++++++++++++++- 5 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 website/src/lib/components/routing/RoutingControlPopup.svelte diff --git a/gpx/src/gpx.ts b/gpx/src/gpx.ts index 3fcb09ea..815ea213 100644 --- a/gpx/src/gpx.ts +++ b/gpx/src/gpx.ts @@ -9,7 +9,11 @@ function cloneJSON(obj: T): T { // An abstract class that groups functions that need to be computed recursively in the GPX file hierarchy export abstract class GPXTreeElement> { - _data: { [key: string]: any } = {}; + _data: { [key: string]: any }; + + constructor() { + this._data = {}; + } abstract isLeaf(): boolean; abstract getChildren(): T[]; @@ -173,7 +177,7 @@ export class GPXFile extends GPXTreeNode{ } clone(): GPXFile { - return new GPXFile(structuredClone(this)); + return new GPXFile(this); } toGeoJSON(): GeoJSON.FeatureCollection { @@ -252,7 +256,7 @@ export class Track extends GPXTreeNode { } clone(): Track { - return new Track(structuredClone(this)); + return new Track(this); } }; @@ -444,7 +448,7 @@ export class TrackSegment extends GPXTreeLeaf { } clone(): TrackSegment { - return new TrackSegment(structuredClone(this)); + return new TrackSegment(this); } }; diff --git a/website/src/lib/components/Map.svelte b/website/src/lib/components/Map.svelte index 32261336..d5356c43 100644 --- a/website/src/lib/components/Map.svelte +++ b/website/src/lib/components/Map.svelte @@ -168,4 +168,18 @@ div :global(.mapboxgl-ctrl-bottom-right) { @apply bottom-9; } + + div :global(.mapboxgl-popup) { + @apply w-fit; + } + + div :global(.mapboxgl-popup-content) { + @apply p-0; + @apply bg-transparent; + @apply shadow-none; + } + + div :global(.mapboxgl-popup-tip) { + @apply drop-shadow-md; + } diff --git a/website/src/lib/components/routing/Routing.svelte b/website/src/lib/components/routing/Routing.svelte index 1c862064..dcb82aab 100644 --- a/website/src/lib/components/routing/Routing.svelte +++ b/website/src/lib/components/routing/Routing.svelte @@ -14,8 +14,13 @@ import { get, type Writable } from 'svelte/store'; import type { GPXFile } from 'gpx'; import { RoutingControls } from './RoutingControls'; + import RoutingControlPopup from './RoutingControlPopup.svelte'; + import { onMount } from 'svelte'; + import mapboxgl from 'mapbox-gl'; let routingControls: Map, RoutingControls> = new Map(); + let popupElement: HTMLElement; + let popup: mapboxgl.Popup | null = null; let selectedFile: Writable | null = null; let active = false; @@ -52,11 +57,23 @@ $: if ($map && selectedFile) { if (!routingControls.has(selectedFile)) { - routingControls.set(selectedFile, new RoutingControls(get(map), selectedFile)); + routingControls.set( + selectedFile, + new RoutingControls(get(map), selectedFile, popup, popupElement) + ); } else { routingControls.get(selectedFile)?.add(); } } + + onMount(() => { + popup = new mapboxgl.Popup({ + closeButton: false, + maxWidth: undefined + }); + popup.setDOMContent(popupElement); + popupElement.classList.remove('hidden'); + }); {#if active} @@ -103,3 +120,5 @@ {/if} + + diff --git a/website/src/lib/components/routing/RoutingControlPopup.svelte b/website/src/lib/components/routing/RoutingControlPopup.svelte new file mode 100644 index 00000000..34c4a4a5 --- /dev/null +++ b/website/src/lib/components/routing/RoutingControlPopup.svelte @@ -0,0 +1,22 @@ + + + diff --git a/website/src/lib/components/routing/RoutingControls.ts b/website/src/lib/components/routing/RoutingControls.ts index c8220d4f..0ed0ec4c 100644 --- a/website/src/lib/components/routing/RoutingControls.ts +++ b/website/src/lib/components/routing/RoutingControls.ts @@ -9,15 +9,20 @@ export class RoutingControls { map: mapboxgl.Map; file: Writable; markers: mapboxgl.Marker[] = []; + popup: mapboxgl.Popup; + popupElement: HTMLElement; unsubscribe: () => void = () => { }; toggleMarkersForZoomLevelAndBoundsBinded: () => void = this.toggleMarkersForZoomLevelAndBounds.bind(this); extendFileBinded: (e: mapboxgl.MapMouseEvent) => void = this.extendFile.bind(this); busy: boolean = false; - constructor(map: mapboxgl.Map, file: Writable) { + constructor(map: mapboxgl.Map, file: Writable, popup: mapboxgl.Popup, popupElement: HTMLElement) { this.map = map; this.file = file; + this.popup = popup; + this.popupElement = popupElement; + this.add(); } @@ -85,7 +90,26 @@ export class RoutingControls { }); anchor.marker = marker; + marker.on('dragstart', () => { + this.map.getCanvas().style.cursor = 'grabbing'; + element.classList.add('cursor-grabbing'); + }); + marker.on('dragend', () => { + this.map.getCanvas().style.cursor = ''; + element.classList.remove('cursor-grabbing'); + }); marker.on('dragend', this.updateAnchor.bind(this)); + marker.getElement().addEventListener('click', (e) => { + marker.setPopup(this.popup); + marker.togglePopup(); + e.stopPropagation(); + + let deleteThisAnchor = this.getDeleteAnchor(anchor); + this.popupElement.addEventListener('delete', deleteThisAnchor); + this.popup.once('close', () => { + this.popupElement.removeEventListener('delete', deleteThisAnchor); + }); + }); this.markers.push(marker); } @@ -197,6 +221,14 @@ export class RoutingControls { this.busy = false; } + getDeleteAnchor(anchor: SimplifiedTrackPoint) { + return () => this.deleteAnchor(anchor); + } + + async deleteAnchor(anchor: SimplifiedTrackPoint) { + console.log('delete', anchor); + } + async extendFile(e: mapboxgl.MapMouseEvent) { if (this.busy) { return;