insertable anchor point

This commit is contained in:
vcoppe
2024-04-26 19:34:46 +02:00
parent 92b77735e9
commit f0b963692c
4 changed files with 93 additions and 4 deletions

View File

@@ -153,7 +153,7 @@
}
div :global(.mapboxgl-ctrl-top-right) {
@apply z-10;
@apply z-20;
@apply flex;
@apply flex-col;
@apply items-end;
@@ -171,6 +171,7 @@
div :global(.mapboxgl-popup) {
@apply w-fit;
@apply z-20;
}
div :global(.mapboxgl-popup-content) {

View File

@@ -23,7 +23,7 @@
let showDirectionMarkers = false;
</script>
<div class="absolute top-2 left-0 right-0 z-10 flex flex-row justify-center pointer-events-none">
<div class="absolute top-2 left-0 right-0 z-20 flex flex-row justify-center pointer-events-none">
<div
class="w-fit flex flex-row flex-wrap mx-16 items-center justify-center p-1 bg-background rounded-md pointer-events-auto shadow-md"
>

View File

@@ -11,9 +11,12 @@ export class RoutingControls {
markers: mapboxgl.Marker[] = [];
popup: mapboxgl.Popup;
popupElement: HTMLElement;
temporaryAnchor: SimplifiedTrackPoint;
unsubscribe: () => void = () => { };
toggleMarkersForZoomLevelAndBoundsBinded: () => void = this.toggleMarkersForZoomLevelAndBounds.bind(this);
showTemporaryAnchorBinded: (e: any) => void = this.showTemporaryAnchor.bind(this);
hideTemporaryAnchorBinded: (e: any) => void = this.hideTemporaryAnchor.bind(this);
appendAnchorBinded: (e: mapboxgl.MapMouseEvent) => void = this.appendAnchor.bind(this);
constructor(map: mapboxgl.Map, file: Writable<GPXFile>, popup: mapboxgl.Popup, popupElement: HTMLElement) {
@@ -22,6 +25,23 @@ export class RoutingControls {
this.popup = popup;
this.popupElement = popupElement;
this.temporaryAnchor = {
point: new TrackPoint({
attributes: {
lon: 0,
lat: 0
}
}),
zoom: 0
};
this.createMarker(this.temporaryAnchor);
let marker = this.markers.pop(); // Remove the temporary anchor from the markers list
marker.getElement().classList.add('z-0'); // Show below the other markers
Object.defineProperty(marker, '_temporary', {
value: true
});
this.add();
}
@@ -29,6 +49,8 @@ export class RoutingControls {
this.map.on('zoom', this.toggleMarkersForZoomLevelAndBoundsBinded);
this.map.on('move', this.toggleMarkersForZoomLevelAndBoundsBinded);
this.map.on('click', this.appendAnchorBinded);
this.map.on('mousemove', get(this.file)._data.layerId, this.showTemporaryAnchorBinded);
this.map.on('mousemove', this.hideTemporaryAnchorBinded);
this.unsubscribe = this.file.subscribe(this.updateControls.bind(this));
}
@@ -64,6 +86,8 @@ export class RoutingControls {
this.map.off('zoom', this.toggleMarkersForZoomLevelAndBoundsBinded);
this.map.off('move', this.toggleMarkersForZoomLevelAndBoundsBinded);
this.map.off('click', this.appendAnchorBinded);
this.map.off('mousemove', get(this.file)._data.layerId, this.showTemporaryAnchorBinded);
this.map.off('mousemove', this.hideTemporaryAnchorBinded);
this.unsubscribe();
}
@@ -80,6 +104,7 @@ export class RoutingControls {
let marker = new mapboxgl.Marker({
draggable: true,
className: 'z-10',
element
}).setLngLat(anchor.point.getCoordinates());
@@ -134,10 +159,34 @@ export class RoutingControls {
});
}
showTemporaryAnchor(e: any) {
this.temporaryAnchor.point.setCoordinates({
lat: e.lngLat.lat,
lon: e.lngLat.lng
});
this.temporaryAnchor.marker.setLngLat(this.temporaryAnchor.point.getCoordinates()).addTo(this.map);
}
hideTemporaryAnchor(e: any) {
if (this.temporaryAnchor.marker?.getElement().classList.contains('cursor-grabbing')) {
return;
}
if (e.point.dist(this.map.project(this.temporaryAnchor.marker?.getLngLat())) < 20) {
return;
}
this.temporaryAnchor.marker.remove();
}
async moveAnchor(e: any) { // Move the anchor and update the route from and to the neighbouring anchors
let marker = e.target;
let anchor = marker._simplified;
if (marker._temporary) { // Temporary anchor, need to find the closest point of the segment and create an anchor for it
anchor = this.getPermanentAnchor(anchor);
marker = anchor.marker;
}
let latlng = marker.getLngLat();
let coordinates = {
lat: latlng.lat,
@@ -165,6 +214,46 @@ export class RoutingControls {
await this.routeBetweenAnchors(anchors, targetCoordinates);
}
getPermanentAnchor(anchor: SimplifiedTrackPoint) {
// Find the closest point closest to the temporary anchor
let minDistance = Number.MAX_VALUE;
let minPoint: TrackPoint | null = null;
for (let segment of get(this.file).getSegments()) {
for (let point of segment.trkpt) {
let dist = distance(point.getCoordinates(), anchor.point.getCoordinates());
if (dist < minDistance) {
minDistance = dist;
minPoint = point;
}
}
}
if (!minPoint) {
return anchor;
}
let segment = minPoint._data.segment;
let newAnchorIndex = segment._data.anchors.findIndex((a) => a.point._data.index >= minPoint._data.index);
if (segment._data.anchors[newAnchorIndex].point._data.index === minPoint._data.index) { // Anchor already exists for this point
return segment._data.anchors[newAnchorIndex];
}
let newAnchor = {
point: minPoint,
zoom: 0
};
this.createMarker(newAnchor);
let marker = this.markers.pop();
marker?.setLngLat(anchor.marker.getLngLat()).addTo(this.map);
segment._data.anchors.splice(newAnchorIndex, 0, newAnchor);
this.markers.splice(newAnchorIndex, 0, marker);
return newAnchor;
}
getDeleteAnchor(anchor: SimplifiedTrackPoint) {
return () => this.deleteAnchor(anchor);
}

View File

@@ -16,7 +16,6 @@
} from 'lucide-svelte';
import { _ } from 'svelte-i18n';
import { derived } from 'svelte/store';
function getToggleTool(tool: Tool) {
return () => toggleTool(tool);
@@ -27,7 +26,7 @@
}
</script>
<div class="absolute top-0 bottom-0 left-0 z-10 flex flex-col justify-center pointer-events-none">
<div class="absolute top-0 bottom-0 left-0 z-20 flex flex-col justify-center pointer-events-none">
<div class="flex flex-row w-screen items-center">
<div
class="h-fit flex flex-col p-1 gap-1 bg-background rounded-md pointer-events-auto shadow-md"