more route drawing

This commit is contained in:
Christian Beutel
2024-04-23 16:11:49 +02:00
parent 8a3894106f
commit b3ed2b1098
10 changed files with 261 additions and 98 deletions

View File

@@ -21,9 +21,14 @@
let L: any; let L: any;
let controlElevation: any; let controlElevation: any;
$: if (trail?.expand.gpx_data !== undefined && controlElevation) { $: gpxData = trail?.expand.gpx_data;
$: if (gpxData && controlElevation) {
controlElevation.clear(); controlElevation.clear();
controlElevation.load(trail.expand.gpx_data); controlElevation.load(gpxData);
}
$: if(options) {
controlElevation?.updateOptions(options)
} }
onMount(async () => { onMount(async () => {
@@ -38,7 +43,7 @@
map = L.map("map", { preferCanvas: true }).setView( map = L.map("map", { preferCanvas: true }).setView(
[trail?.lat ?? 0, trail?.lon ?? 0], [trail?.lat ?? 0, trail?.lon ?? 0],
16, 3,
); );
map!.attributionControl.setPrefix(false); map!.attributionControl.setPrefix(false);
@@ -77,9 +82,9 @@
ruler: false, ruler: false,
legend: true, legend: true,
// Toggle "leaflet-almostover" integration // Toggle "leaflet-almostover" integration
almostOver: true, almostOver: false,
// Toggle "leaflet-distance-markers" integration // Toggle "leaflet-distance-markers" integration
distanceMarkers: false, distanceMarkers: { lazy: false, distance: false, direction: true, offset: 500 },
// Toggle "leaflet-edgescale" integration // Toggle "leaflet-edgescale" integration
edgeScale: false, edgeScale: false,
// Toggle "leaflet-hotline" integration // Toggle "leaflet-hotline" integration
@@ -91,11 +96,14 @@
wptLabels: false, wptLabels: false,
preferCanvas: true, preferCanvas: true,
trkStart: { trkStart: {
interactive: false,
className: "hihi",
icon: L.AwesomeMarkers.icon({ icon: L.AwesomeMarkers.icon({
icon: "circle-half-stroke", icon: "circle-half-stroke",
prefix: "fa", prefix: "fa",
markerColor: "cadetblue", markerColor: "cadetblue",
iconColor: "white", iconColor: "white",
className: "awesome-marker pointer-events-none"
}), }),
}, },
trkEnd: { trkEnd: {
@@ -104,9 +112,11 @@
prefix: "fa", prefix: "fa",
markerColor: "cadetblue", markerColor: "cadetblue",
iconColor: "white", iconColor: "white",
className: "awesome-marker pointer-events-none"
}), }),
}, },
graticule: false, graticule: false,
drawing: false
}; };
const elevation_options = Object.assign( const elevation_options = Object.assign(

View File

@@ -1,3 +1,5 @@
import type { LatLng, Marker } from "leaflet";
interface ValhallaRouteResponse { interface ValhallaRouteResponse {
trip: { trip: {
legs: { legs: {
@@ -10,4 +12,11 @@ interface ValhallaHeightResponse {
height: number[]; height: number[];
} }
export { type ValhallaRouteResponse, type ValhallaHeightResponse } interface ValhallaAnchor {
id: string,
lat: number,
lon: number,
marker?: Marker
}
export { type ValhallaRouteResponse, type ValhallaHeightResponse, type ValhallaAnchor }

View File

@@ -2,16 +2,21 @@ import GPX from "$lib/models/gpx/gpx";
import type Track from "$lib/models/gpx/track"; import type Track from "$lib/models/gpx/track";
import TrackSegment from "$lib/models/gpx/track-segment"; import TrackSegment from "$lib/models/gpx/track-segment";
import Waypoint from "$lib/models/gpx/waypoint"; import Waypoint from "$lib/models/gpx/waypoint";
import { type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla"; import { type ValhallaAnchor, type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla";
import { ClientResponseError } from "pocketbase"; import { ClientResponseError } from "pocketbase";
const emtpyTrack: Track = { trkseg: [] } const emtpyTrack: Track = { trkseg: [] }
export let route: GPX = new GPX({ trk: [emtpyTrack] }); export let route: GPX = new GPX({ trk: [emtpyTrack] });
export let anchors: ValhallaAnchor[] = [];
export function clearRoute() { export function clearRoute() {
route = new GPX({ trk: [emtpyTrack] }); route = new GPX({ trk: [emtpyTrack] });
anchors = [];
}
export function setRoute(newRoute: GPX) {
route = newRoute
} }
export async function calculateRouteBetween(startLat: number, startLon: number, endLat: number, endLon: number) { export async function calculateRouteBetween(startLat: number, startLon: number, endLat: number, endLon: number) {

View File

@@ -47,7 +47,7 @@ export async function gpx2trail(gpxString: string) {
trail.elevation_gain = totals.elevationGain; trail.elevation_gain = totals.elevationGain;
trail.distance = totals.distance trail.distance = totals.distance
return trail return {gpx: gpx, trail: trail}
} }
export function fromKML(kmlData: string) { export function fromKML(kmlData: string) {

View File

@@ -1,5 +1,5 @@
import type { Waypoint } from "$lib/models/waypoint"; import type { Waypoint } from "$lib/models/waypoint";
import type { Icon, LeafletEvent, Map, Marker } from "leaflet"; import type { Icon, LatLng, LeafletEvent, Map, Marker } from "leaflet";
export function createMarkerFromWaypoint(L: any, waypoint: Waypoint, onDragEnd?: (event: LeafletEvent) => void): Marker { export function createMarkerFromWaypoint(L: any, waypoint: Waypoint, onDragEnd?: (event: LeafletEvent) => void): Marker {
const fontAwesomeIcon = L.AwesomeMarkers.icon({ const fontAwesomeIcon = L.AwesomeMarkers.icon({
@@ -28,10 +28,35 @@ export function createMarkerFromWaypoint(L: any, waypoint: Waypoint, onDragEnd?:
if (onDragEnd) { if (onDragEnd) {
marker.on("dragend", onDragEnd); marker.on("dragend", onDragEnd);
} }
return marker; return marker;
} }
export function createAnchorMarker(L: any, lat: number, lon: number, index: number, onDeleteClick: () => void, onDragEnd: (event: LeafletEvent) => void): Marker {
const anchorIconElement = document.createElement("span")
anchorIconElement.textContent = "" + index
const anchorIcon = L.divIcon({
html: anchorIconElement,
iconSize: [24, 24],
className: "leaflet-anchor"
});
const deleteButton = document.createElement("button");
deleteButton.className = "btn-icon fa fa-trash text-red-500";
deleteButton.addEventListener("click", onDeleteClick)
const marker = L.marker([lat, lon], {
icon: anchorIcon,
draggable: true,
})
.bindPopup(
deleteButton
);
marker.on("dragend", onDragEnd);
return marker
}
export function calculatePixelPerMeter(map: Map, meters: number) { export function calculatePixelPerMeter(map: Map, meters: number) {
const y = map.getSize().y; const y = map.getSize().y;
const x = map.getSize().x; const x = map.getSize().x;
@@ -65,7 +90,7 @@ export function calculateScaleFactor(map: Map) {
); );
const screenMetersPer100Pixels = _pxTOmm()(100) / 1000; const screenMetersPer100Pixels = _pxTOmm()(100) / 1000;
const scaleFactor = realWorlMetersPer100Pixels / screenMetersPer100Pixels const scaleFactor = realWorlMetersPer100Pixels / screenMetersPer100Pixels
return scaleFactor return scaleFactor

View File

@@ -1,5 +1,5 @@
import * as _ from './utils';
import { Options } from './options'; import { Options } from './options';
import * as _ from './utils';
// "leaflet-i18n" fallback // "leaflet-i18n" fallback
if (!L._ || !L.i18n) { if (!L._ || !L.i18n) {
@@ -26,6 +26,15 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
__modulesFolder: '/vendor/leaflet-elevation/src/handlers/', __modulesFolder: '/vendor/leaflet-elevation/src/handlers/',
__btnIcon: '/vendor/leaflet-elevation/images/elevation.svg', __btnIcon: '/vendor/leaflet-elevation/images/elevation.svg',
updateOptions(options) {
Object.assign(this.options, options)
if (!this.options.showStartEnd) {
this._circleMarkers.remove();
} else if (this._data.length) {
this._circleMarkers.addTo(this._map);
}
},
/* /*
* Add data to the diagram either from GPX or GeoJSON and update the axis domain and data * Add data to the diagram either from GPX or GeoJSON and update the axis domain and data
*/ */
@@ -171,7 +180,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
* Initialize chart control "options" and "container". * Initialize chart control "options" and "container".
*/ */
initialize(opts) { initialize(opts) {
// opts = L.setOptions(this, opts); // opts = L.setOptions(this, opts);
// Fixes: https://github.com/Raruto/leaflet-elevation/pull/240 // Fixes: https://github.com/Raruto/leaflet-elevation/pull/240
@@ -198,7 +206,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
if (opts.trkStart) this._start.addTo(this._circleMarkers); if (opts.trkStart) this._start.addTo(this._circleMarkers);
if (opts.trkEnd) this._end.addTo(this._circleMarkers); if (opts.trkEnd) this._end.addTo(this._circleMarkers);
this._markedSegments.setStyle(opts.polylineSegments); this._markedSegments.setStyle(opts.polylineSegments);
// Leaflet canvas renderer colors // Leaflet canvas renderer colors
@@ -488,7 +495,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
]).then(() => { ]).then(() => {
if (this.options.polyline) { if (this.options.polyline) {
this._layers.addLayer(layer.addTo(map)); // hotfix for: https://github.com/Raruto/leaflet-elevation/issues/233 this._layers.addLayer(layer.addTo(map)); // hotfix for: https://github.com/Raruto/leaflet-elevation/issues/233
this._circleMarkers.addTo(map); if (this.options.showStartEnd) {
this._circleMarkers.addTo(map);
}
} }
if (this.options.autofitBounds) { if (this.options.autofitBounds) {
this.fitBounds(layer.getBounds()); this.fitBounds(layer.getBounds());
@@ -1254,7 +1263,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
* Update the position/height indicator marker drawn onto the map * Update the position/height indicator marker drawn onto the map
*/ */
_updateMarker(item) { _updateMarker(item) {
if (this._marker) { if (this._marker && this.options.mapTooltip) {
this._marker.update({ this._marker.update({
map: this._map, map: this._map,
item: item, item: item,

View File

@@ -347,4 +347,15 @@
.leaflet-popup-content { .leaflet-popup-content {
width: max-content !important; width: max-content !important;
max-width: 100%; max-width: 100%;
}
.leaflet-anchor {
background-color: #fff;
border: 2px solid black;
width: 24px;
height: 24px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
text-align: center;
} }

View File

@@ -50,6 +50,8 @@ export var Options = {
time: true, time: true,
timeFactor: 3600, timeFactor: 3600,
timestamps: false, timestamps: false,
showStartEnd: true,
mapTooltip: true,
trkStart: { className: 'start-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#00d800', fillOpacity: 1, interactive: false }, trkStart: { className: 'start-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#00d800', fillOpacity: 1, interactive: false },
trkEnd: { className: 'end-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#ff0606', fillOpacity: 1, interactive: false }, trkEnd: { className: 'end-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#ff0606', fillOpacity: 1, interactive: false },
waypoints: true, waypoints: true,

View File

@@ -7,13 +7,13 @@ import { ClientResponseError } from "pocketbase";
export async function PUT(event: RequestEvent) { export async function PUT(event: RequestEvent) {
try { try {
const data = await event.request.blob(); const data = await event.request.blob();
const gpx = await data.text(); const gpxString = await data.text();
if (!gpx.length) { if (!gpxString.length) {
throw new ClientResponseError({ status: 400, response: { message: "Empty file" } }) throw new ClientResponseError({ status: 400, response: { message: "Empty file" } })
} }
let trail: Trail; let trail: Trail;
try { try {
trail = await gpx2trail(gpx); trail = (await gpx2trail(gpxString)).trail;
} catch (e: any) { } catch (e: any) {
throw new ClientResponseError({ status: 400, response: { message: "Invalid GPX file" } }) throw new ClientResponseError({ status: 400, response: { message: "Invalid GPX file" } })
} }

View File

@@ -13,9 +13,11 @@
import PhotoPicker from "$lib/components/trail/photo_picker.svelte"; import PhotoPicker from "$lib/components/trail/photo_picker.svelte";
import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte"; import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte";
import WaypointModal from "$lib/components/waypoint/waypoint_modal.svelte"; import WaypointModal from "$lib/components/waypoint/waypoint_modal.svelte";
import GPX from "$lib/models/gpx/gpx";
import type { List } from "$lib/models/list"; import type { List } from "$lib/models/list";
import { SummitLog } from "$lib/models/summit_log"; import { SummitLog } from "$lib/models/summit_log";
import { Trail } from "$lib/models/trail"; import { Trail } from "$lib/models/trail";
import type { ValhallaAnchor } from "$lib/models/valhalla";
import { Waypoint } from "$lib/models/waypoint"; import { Waypoint } from "$lib/models/waypoint";
import { categories } from "$lib/stores/category_store"; import { categories } from "$lib/stores/category_store";
import { import {
@@ -32,12 +34,14 @@
trails_update, trails_update,
} from "$lib/stores/trail_store"; } from "$lib/stores/trail_store";
import { import {
anchors,
appendToRoute, appendToRoute,
calculateRouteBetween, calculateRouteBetween,
clearRoute, clearRoute,
deleteFromRoute, deleteFromRoute,
editRoute, editRoute,
route, route,
setRoute,
} from "$lib/stores/valhalla_store"; } from "$lib/stores/valhalla_store";
import { waypoint } from "$lib/stores/waypoint_store"; import { waypoint } from "$lib/stores/waypoint_store";
import { getFileURL } from "$lib/util/file_util"; import { getFileURL } from "$lib/util/file_util";
@@ -47,10 +51,13 @@
formatTimeHHMM, formatTimeHHMM,
} from "$lib/util/format_util"; } from "$lib/util/format_util";
import { fromKML, fromTCX, gpx2trail } from "$lib/util/gpx_util"; import { fromKML, fromTCX, gpx2trail } from "$lib/util/gpx_util";
import { createMarkerFromWaypoint } from "$lib/util/leaflet_util"; import {
createAnchorMarker,
createMarkerFromWaypoint,
} from "$lib/util/leaflet_util";
import { createForm } from "$lib/vendor/svelte-form-lib"; import { createForm } from "$lib/vendor/svelte-form-lib";
import cryptoRandomString from "crypto-random-string"; import cryptoRandomString from "crypto-random-string";
import type { LeafletMouseEvent, Map } from "leaflet"; import type { DivIcon, LatLng, LeafletMouseEvent, Map } from "leaflet";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { array, number, object, string } from "yup"; import { array, number, object, string } from "yup";
@@ -73,6 +80,7 @@
let gpxFile: File | Blob | null = null; let gpxFile: File | Blob | null = null;
let drawingActive = false; let drawingActive = false;
let overwriteGPX = false;
const trailSchema = object<Trail>({ const trailSchema = object<Trail>({
id: string().optional(), id: string().optional(),
@@ -126,6 +134,13 @@
submittedTrail.photos = submittedTrail.photos.filter( submittedTrail.photos = submittedTrail.photos.filter(
(p) => !p.startsWith("data:image/svg+xml;base64"), (p) => !p.startsWith("data:image/svg+xml;base64"),
); );
if ($form.expand.gpx_data && overwriteGPX) {
gpxFile = new Blob([$form.expand.gpx_data], {
type: "text/xml",
});
}
if (!submittedTrail.id) { if (!submittedTrail.id) {
const createdTrail = await trails_create( const createdTrail = await trails_create(
submittedTrail, submittedTrail,
@@ -165,8 +180,18 @@
L = (await import("leaflet")).default; L = (await import("leaflet")).default;
await import("leaflet.awesome-markers"); await import("leaflet.awesome-markers");
$form.lat = 47.74604748696788; // $form.lat = 47.74604748696788;
$form.lon = 11.588988304138185; // $form.lon = 11.588988304138185;
clearAnchorMarker();
clearRoute();
if ($form.expand.gpx_data) {
const gpx = await GPX.parse($form.expand.gpx_data);
if (!(gpx instanceof Error)) {
setRoute(gpx);
initRouteAnchors(gpx);
}
}
}); });
function openFileBrowser() { function openFileBrowser() {
@@ -183,7 +208,10 @@
} }
clearWaypoints(); clearWaypoints();
clearAnchorMarker();
clearRoute(); clearRoute();
drawingActive = false;
overwriteGPX = false;
var reader = new FileReader(); var reader = new FileReader();
reader.readAsText(selectedFile); reader.readAsText(selectedFile);
@@ -202,9 +230,13 @@
gpxFile = selectedFile; gpxFile = selectedFile;
} }
try { try {
$form = await gpx2trail(gpxData); const parseResult = await gpx2trail(gpxData);
$form = parseResult.trail;
$form.expand.gpx_data = gpxData; $form.expand.gpx_data = gpxData;
setRoute(parseResult.gpx);
initRouteAnchors(parseResult.gpx);
for (const waypoint of $form.expand.waypoints) { for (const waypoint of $form.expand.waypoints) {
saveWaypoint(waypoint); saveWaypoint(waypoint);
} }
@@ -245,6 +277,32 @@
$form.waypoints = []; $form.waypoints = [];
} }
function clearAnchorMarker() {
for (const anchor of anchors) {
anchor.marker?.remove();
}
}
function initRouteAnchors(gpx: GPX) {
const segments = gpx.trk?.at(0)?.trkseg ?? [];
for (let i = 0; i < segments.length; i++) {
const segment = segments[i];
const points = segment.trkpt ?? [];
if (points.length > 0) {
addAnchor(points[0].$.lat!, points[0].$.lon!, false);
}
if (i == segments.length - 1) {
addAnchor(
points[points.length - 1].$.lat!,
points[points.length - 1].$.lon!,
false,
);
}
}
}
function openMarkerPopup(waypoint: Waypoint) { function openMarkerPopup(waypoint: Waypoint) {
waypoint.marker?.openPopup(); waypoint.marker?.openPopup();
} }
@@ -273,28 +331,6 @@
$form.expand.waypoints.splice(index, 1); $form.expand.waypoints.splice(index, 1);
$form.waypoints.splice(index, 1); $form.waypoints.splice(index, 1);
$form.expand.waypoints = $form.expand.waypoints; $form.expand.waypoints = $form.expand.waypoints;
if (drawingActive) {
if (index == 0) {
deleteFromRoute(index);
updateTrailWithRouteData();
const nextWaypoint = $form.expand.waypoints[index];
nextWaypoint.icon = "circle-half-stroke";
saveWaypoint(nextWaypoint);
} else if (index == $form.expand.waypoints.length) {
deleteFromRoute(index - 1);
updateTrailWithRouteData();
if ($form.expand.waypoints.length > 1) {
const previousWaypoint = $form.expand.waypoints[index - 1];
previousWaypoint.icon = "flag-checkered";
saveWaypoint(previousWaypoint);
}
} else {
deleteFromRoute(index - 1);
recalculateRoute(index);
}
}
} }
function saveWaypoint(savedWaypoint: Waypoint) { function saveWaypoint(savedWaypoint: Waypoint) {
@@ -320,10 +356,6 @@
editableWaypoint!.lat = position.lat; editableWaypoint!.lat = position.lat;
editableWaypoint!.lon = position.lng; editableWaypoint!.lon = position.lng;
$form.expand.waypoints = [...$form.expand.waypoints]; $form.expand.waypoints = [...$form.expand.waypoints];
if (drawingActive) {
recalculateRoute(editableWaypointIndex);
}
}); });
marker.addTo(map); marker.addTo(map);
@@ -386,42 +418,37 @@
function startDrawing() { function startDrawing() {
drawingActive = true; drawingActive = true;
if (!route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.length) { if (!route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.length) {
$form.expand.gpx_data = ""; }
clearWaypoints(); for (const anchor of anchors) {
anchor.marker?.addTo(map);
} }
} }
function stopDrawing() { function stopDrawing() {
drawingActive = false; drawingActive = false;
for (const anchor of anchors) {
anchor.marker?.remove();
}
} }
async function handleMapClick(e: LeafletMouseEvent) { async function handleMapClick(e: LeafletMouseEvent) {
if (!drawingActive) { if (!drawingActive) {
return; return;
} }
const waypointCount = $form.expand.waypoints.length; const anchorCount = anchors.length;
const wp = new Waypoint(e.latlng.lat, e.latlng.lng, { if (anchorCount == 0) {
name: `${$_("waypoints", { values: { n: 1 } })} ${waypointCount + 1}`, addAnchor(e.latlng.lat, e.latlng.lng);
icon: waypointCount ? "flag-checkered" : "circle-half-stroke",
});
if (waypointCount == 0) {
saveWaypoint(wp);
} else { } else {
const previousWaypoint = $form.expand.waypoints[waypointCount - 1]; const previousAnchor = anchors[anchorCount - 1];
try { try {
const routeWaypoints = await calculateRouteBetween( const routeWaypoints = await calculateRouteBetween(
previousWaypoint.lat, previousAnchor.lat,
previousWaypoint.lon, previousAnchor.lon,
e.latlng.lat, e.latlng.lat,
e.latlng.lng, e.latlng.lng,
); );
appendToRoute(routeWaypoints); appendToRoute(routeWaypoints);
saveWaypoint(wp); addAnchor(e.latlng.lat, e.latlng.lng);
if (waypointCount > 1) {
previousWaypoint.icon = "circle";
saveWaypoint(previousWaypoint);
}
updateTrailWithRouteData(); updateTrailWithRouteData();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@@ -434,39 +461,104 @@
} }
} }
async function recalculateRoute(waypointIndex: number) { function addAnchor(lat: number, lon: number, addtoMap: boolean = true) {
const waypoint = $form.expand.waypoints[waypointIndex]; const anchor: ValhallaAnchor = {
let nextWaypoints; id: cryptoRandomString({ length: 15 }),
let previousWaypoints; lat: lat,
if (waypointIndex < $form.expand.waypoints.length - 1) { lon: lon,
const nextWaypoint = $form.expand.waypoints[waypointIndex + 1]; };
const marker = createAnchorMarker(
L,
lat,
lon,
anchors.length + 1,
() => {
removeAnchor(anchors.findIndex((a) => a.id == anchor.id));
},
(_) => {
if (!drawingActive) {
return;
}
const position = marker.getLatLng();
anchor.lat = position.lat;
anchor.lon = position.lng;
recalculateRoute(anchors.findIndex((a) => a.id == anchor.id));
},
);
if (addtoMap) {
marker.addTo(map);
}
anchor.marker = marker;
anchors.push(anchor);
}
nextWaypoints = await calculateRouteBetween( function removeAnchor(anchorIndex: number) {
waypoint.lat, if (!drawingActive) {
waypoint.lon, return;
nextWaypoint.lat, }
nextWaypoint.lon, anchors[anchorIndex]?.marker?.remove();
anchors.splice(anchorIndex, 1);
for (let i = anchorIndex; i < anchors.length; i++) {
const anchor = anchors[i];
const markerIcon = anchor.marker?.getIcon() as DivIcon | undefined;
if (markerIcon) {
const markerText =
(markerIcon.options.html as HTMLSpanElement).textContent ??
"0";
const markerIndex = parseInt(markerText);
(markerIcon.options.html as HTMLSpanElement).textContent =
markerIndex - 1 + "";
}
}
if (anchorIndex == 0) {
deleteFromRoute(anchorIndex);
updateTrailWithRouteData();
} else if (anchorIndex == anchors.length) {
deleteFromRoute(anchorIndex - 1);
updateTrailWithRouteData();
} else {
deleteFromRoute(anchorIndex - 1);
recalculateRoute(anchorIndex);
}
}
async function recalculateRoute(anchorIndex: number) {
const anchor = anchors[anchorIndex];
if (!anchor) {
return;
}
let nextRouteSegment;
let previousRouteSegment;
if (anchorIndex < anchors.length - 1) {
const nextAnchor = anchors[anchorIndex + 1];
nextRouteSegment = await calculateRouteBetween(
anchor.lat,
anchor.lon,
nextAnchor.lat,
nextAnchor.lon,
); );
} }
if (waypointIndex > 0) { if (anchorIndex > 0) {
const previousWaypoint = $form.expand.waypoints[waypointIndex - 1]; const previousAnchor = anchors[anchorIndex - 1];
previousWaypoints = await calculateRouteBetween( previousRouteSegment = await calculateRouteBetween(
previousWaypoint.lat, previousAnchor.lat,
previousWaypoint.lon, previousAnchor.lon,
waypoint.lat, anchor.lat,
waypoint.lon, anchor.lon,
); );
} }
if (nextWaypoints) { if (nextRouteSegment) {
editRoute(waypointIndex, nextWaypoints); editRoute(anchorIndex, nextRouteSegment);
} }
if (previousWaypoints) { if (previousRouteSegment) {
editRoute(waypointIndex - 1, previousWaypoints); editRoute(anchorIndex - 1, previousRouteSegment);
} }
updateTrailWithRouteData(); updateTrailWithRouteData();
} }
function updateTrailWithRouteData() { function updateTrailWithRouteData() {
overwriteGPX = true;
const totals = route.getTotals(); const totals = route.getTotals();
$form.distance = totals.distance; $form.distance = totals.distance;
$form.duration = totals.duration; $form.duration = totals.duration;
@@ -720,11 +812,11 @@
trail={$form} trail={$form}
crosshair={drawingActive} crosshair={drawingActive}
options={{ options={{
hotline: true, autofitBounds: !drawingActive,
autofitBounds: false, mapTooltip: !drawingActive,
trkStart: false, speed: !drawingActive,
trkEnd: false, speedFactor: drawingActive ? 0 : 1,
speed: false, showStartEnd: !drawingActive,
}} }}
bind:map bind:map
on:click={(e) => handleMapClick(e.detail)} on:click={(e) => handleMapClick(e.detail)}
@@ -742,11 +834,11 @@
></ListSelectModal> ></ListSelectModal>
<style> <style>
:global(#map) { #map {
height: calc(400px); height: calc(400px);
} }
@media only screen and (min-width: 768px) { @media only screen and (min-width: 768px) {
:global(#map), #map,
form { form {
height: calc(100vh - 124px); height: calc(100vh - 124px);
} }