mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-01 08:12:32 +00:00
insertable anchor point
This commit is contained in:
@@ -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) {
|
||||
|
@@ -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"
|
||||
>
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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"
|
||||
|
Reference in New Issue
Block a user