Improve trail planning: option to re-order route anchors (#1007)

* trail anchor list added

* add search location card to extend route endpoint in drawing mode

* add POI popup endpoint action in route drawing mode

* fix anchor stats, improve anchor list entries and refine route marker behavior

* fix map marker spinner

* docs updated

* fix spinner when delete an anchor

* further improvements

* fix adding first anchor from POI

* optimize drag handle area

---------

Co-authored-by: Flomp <Flomp@users.noreply.github.com>
This commit is contained in:
slothful-vassal
2026-06-06 11:56:12 +02:00
committed by GitHub
parent 14ebaa0d04
commit 44cd092065
32 changed files with 1792 additions and 192 deletions

View File

@@ -6,6 +6,7 @@ import Waypoint from "$lib/models/gpx/waypoint";
import { type RoutingOptions, type ValhallaAnchor, type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla";
import { APIError } from "$lib/util/api_util";
import { decodePolyline, encodePolyline } from "$lib/util/polyline_util";
import { renderValhallaAnchorMarker, valhallaAnchorTitle } from "$lib/util/valhalla_anchor_util";
import { applyChangeset, diff, revertChangeset, type Changeset } from 'json-diff-ts';
import type { LngLat } from "maplibre-gl";
import { _ } from "svelte-i18n";
@@ -16,8 +17,8 @@ const emtpyTrack = new Track({ trkseg: [] })
class ValhallaStore {
route: GPX = $state(new GPX({ trk: [emtpyTrack] }));
anchors: ValhallaAnchor[] = $state([]);
undoStack: { delta: Changeset, reverseDelta: Changeset }[] = $state([]);
redoStack: { delta: Changeset, reverseDelta: Changeset }[] = $state([]);
undoStack: { delta: Changeset, reverseDelta: Changeset, anchorsBefore?: ValhallaAnchor[], anchorsAfter?: ValhallaAnchor[] }[] = $state([]);
redoStack: { delta: Changeset, reverseDelta: Changeset, anchorsBefore?: ValhallaAnchor[], anchorsAfter?: ValhallaAnchor[] }[] = $state([]);
}
export const valhallaStore = new ValhallaStore();
@@ -179,14 +180,21 @@ export function reverseRoute() {
if (!a.marker) {
return;
}
a.marker.getElement().textContent = "" + (i + 1);
renderValhallaAnchorMarker(
a.marker.getElement(),
i,
valhallaStore.anchors.length,
);
const anchorPopupHeading = a.marker
.getPopup()
._content.getElementsByTagName("h5")[0];
if (anchorPopupHeading) {
anchorPopupHeading.textContent =
get(_)("route-point") + " #" + (i + 1);
anchorPopupHeading.textContent = valhallaAnchorTitle(
i,
valhallaStore.anchors.length,
get(_),
);
}
});
}
@@ -235,8 +243,8 @@ export async function splitSegment(index: number, pos: LngLat) {
const firstSegmentPoints = [...points.slice(0, bestSplitIndex), intersectionPoint];
const secondSegmentPoints = [intersectionPoint, ...points.slice(bestSplitIndex)];
editRoute(index, firstSegmentPoints)
insertIntoRoute(secondSegmentPoints, index + 1)
await editRoute(index, firstSegmentPoints)
await insertIntoRoute(secondSegmentPoints, index + 1)
}
@@ -263,21 +271,30 @@ export function normalizeRouteTime() {
export function undo() {
const historyItem = valhallaStore.undoStack.pop()
if (!historyItem) {
return
return undefined
}
valhallaStore.redoStack.push(historyItem)
valhallaStore.route = applyChangeset(valhallaStore.route, historyItem.reverseDelta);
valhallaStore.route.features = valhallaStore.route.getTotals();
return historyItem;
}
export function revertRouteChange() {
const historyItem = valhallaStore.undoStack.pop();
if (!historyItem) return;
valhallaStore.route = applyChangeset(valhallaStore.route, historyItem.reverseDelta);
valhallaStore.route.features = valhallaStore.route.getTotals();
}
export function redo() {
const historyItem = valhallaStore.redoStack.pop()
if (!historyItem) {
return
return undefined
}
valhallaStore.undoStack.push(historyItem)
valhallaStore.route = applyChangeset(valhallaStore.route, historyItem.delta);
valhallaStore.route.features = valhallaStore.route.getTotals();
return historyItem;
}