adds route editing capabilities
This commit is contained in:
@@ -53,8 +53,6 @@
|
||||
: null;
|
||||
let selectedTrail: Trail | null = null;
|
||||
|
||||
let activeTrailIndex: number = -1;
|
||||
|
||||
let loading: boolean = false;
|
||||
let loadingNextPage: boolean = false;
|
||||
let filterExpanded: boolean = false;
|
||||
@@ -63,6 +61,12 @@
|
||||
|
||||
let userQuery = "";
|
||||
|
||||
$: selectedTrailIndex = selectedTrail
|
||||
? (selectedList?.expand?.trails?.indexOf(selectedTrail) ?? null)
|
||||
: null;
|
||||
|
||||
$: selectedTrailWaypoints = selectedTrail?.expand?.waypoints;
|
||||
|
||||
onMount(() => {
|
||||
if ($page.url.searchParams.get("list") && selectedList) {
|
||||
setCurrentList(selectedList);
|
||||
@@ -121,7 +125,6 @@
|
||||
loadAllListsOnNextBack = false;
|
||||
}
|
||||
if (selectedTrail) {
|
||||
mapWithElevation.unFocusTrail(selectedTrail);
|
||||
selectedTrail = null;
|
||||
} else if (selectedList) {
|
||||
selectedList = null;
|
||||
@@ -135,7 +138,6 @@
|
||||
|
||||
function selectTrail(trail: Trail) {
|
||||
selectedTrail = trail;
|
||||
mapWithElevation.focusTrail(trail);
|
||||
window.scrollTo({ top: 0 });
|
||||
}
|
||||
|
||||
@@ -353,14 +355,15 @@
|
||||
<div id="trail-map" class:hidden={!showMap}>
|
||||
<MapWithElevationMaplibre
|
||||
trails={selectedList?.expand?.trails ?? []}
|
||||
waypoints={selectedTrailWaypoints}
|
||||
bind:map
|
||||
bind:this={mapWithElevation}
|
||||
bind:markers
|
||||
activeTrail={selectedTrailIndex}
|
||||
fitBounds="animate"
|
||||
on:select={(e) => {
|
||||
selectedTrail = e.detail;
|
||||
}}
|
||||
bind:activeTrail={activeTrailIndex}
|
||||
showInfoPopup={true}
|
||||
showTerrain={true}
|
||||
></MapWithElevationMaplibre>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
<div id="trail-details" class="sticky top-[62px]">
|
||||
<MapWithElevationMaplibre
|
||||
trails={[$trail]}
|
||||
waypoints={$trail.expand?.waypoints}
|
||||
activeTrail={0}
|
||||
bind:markers
|
||||
showTerrain={true}
|
||||
></MapWithElevationMaplibre>
|
||||
|
||||
@@ -516,6 +516,8 @@
|
||||
<div class="basis-full">
|
||||
<MapWithElevationMaplibre
|
||||
trails={[$trail]}
|
||||
waypoints={$trail.expand?.waypoints}
|
||||
activeTrail={0}
|
||||
on:zoom={(e) => updateScale(e.detail)}
|
||||
bind:map
|
||||
{showGrid}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
const file = files[i];
|
||||
try {
|
||||
uploadProgress.set((progress += 100 / (files.length * 2)));
|
||||
await trails_upload(file);
|
||||
// await trails_upload(file);
|
||||
} catch (e) {
|
||||
errorsThrown += 1;
|
||||
show_toast({
|
||||
@@ -98,14 +98,7 @@
|
||||
uploading = false;
|
||||
jsConfetti.addConfetti({
|
||||
confettiRadius: 4,
|
||||
confettiColors: [
|
||||
"#F4C842",
|
||||
"#3C9D9B",
|
||||
"#D1C4E9",
|
||||
"#FF6F61",
|
||||
"#A9D9C1",
|
||||
"#F2F2F2",
|
||||
],
|
||||
emojis: ['🍃', '🍁'],
|
||||
});
|
||||
}, 500);
|
||||
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
} from "$lib/stores/trail_store.js";
|
||||
import {
|
||||
anchors,
|
||||
appendToRoute,
|
||||
calculateRouteBetween,
|
||||
clearRoute,
|
||||
deleteFromRoute,
|
||||
editRoute,
|
||||
insertIntoRoute,
|
||||
route,
|
||||
setRoute,
|
||||
} from "$lib/stores/valhalla_store";
|
||||
@@ -54,6 +54,9 @@
|
||||
} from "$lib/util/format_util";
|
||||
import { fromFile, gpx2trail } from "$lib/util/gpx_util";
|
||||
|
||||
import emptyStateTrailDark from "$lib/assets/svgs/empty_states/empty_state_trail_dark.svg";
|
||||
import emptyStateTrailLight from "$lib/assets/svgs/empty_states/empty_state_trail_light.svg";
|
||||
import { theme } from "$lib/stores/theme_store.js";
|
||||
import {
|
||||
createAnchorMarker,
|
||||
createMarkerFromWaypoint,
|
||||
@@ -67,9 +70,6 @@
|
||||
import { backInOut } from "svelte/easing";
|
||||
import { scale } from "svelte/transition";
|
||||
import { z } from "zod";
|
||||
import emptyStateTrailDark from "$lib/assets/svgs/empty_states/empty_state_trail_dark.svg";
|
||||
import emptyStateTrailLight from "$lib/assets/svgs/empty_states/empty_state_trail_light.svg";
|
||||
import { theme } from "$lib/stores/theme_store.js";
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
|
||||
let drawingActive = false;
|
||||
let overwriteGPX = false;
|
||||
let draggingMarker = false;
|
||||
|
||||
const ClientTrailCreateSchema = TrailCreateSchema.extend({
|
||||
expand: z
|
||||
@@ -171,7 +172,7 @@
|
||||
?.trkpt?.at(0)?.$.lon;
|
||||
}
|
||||
|
||||
if (!form.id) {
|
||||
if ($page.params.id === "new") {
|
||||
const createdTrail = await trails_create(
|
||||
form as Trail,
|
||||
photoFiles,
|
||||
@@ -213,6 +214,19 @@
|
||||
if ($formData.expand!.gpx_data) {
|
||||
const gpx = await GPX.parse($formData.expand!.gpx_data);
|
||||
if (!(gpx instanceof Error)) {
|
||||
if (gpx.rte && !gpx.trk) {
|
||||
gpx.trk = [
|
||||
{
|
||||
trkseg: [
|
||||
{
|
||||
trkpt: gpx.rte?.at(0)?.rtept,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
gpx.rte = undefined;
|
||||
}
|
||||
|
||||
setRoute(gpx);
|
||||
initRouteAnchors(gpx);
|
||||
}
|
||||
@@ -245,7 +259,7 @@
|
||||
const prevId = $formData.id;
|
||||
const parseResult = await gpx2trail(gpxData, selectedFile.name);
|
||||
setFields(parseResult.trail);
|
||||
$formData.id = prevId;
|
||||
$formData.id = prevId ?? cryptoRandomString({ length: 15 });
|
||||
$formData.expand!.gpx_data = gpxData;
|
||||
setFields(
|
||||
"category",
|
||||
@@ -273,12 +287,20 @@
|
||||
|
||||
$formData.expand!.summit_logs.push(log);
|
||||
|
||||
if (parseResult.gpx.rte?.length && !parseResult.gpx.trk) {
|
||||
parseResult.gpx.trk = [
|
||||
{
|
||||
trkseg: [
|
||||
{
|
||||
trkpt: parseResult.gpx.rte?.at(0)?.rtept,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
parseResult.gpx.rte = undefined;
|
||||
}
|
||||
setRoute(parseResult.gpx);
|
||||
initRouteAnchors(parseResult.gpx);
|
||||
|
||||
for (const waypoint of $formData.expand!.waypoints) {
|
||||
saveWaypoint(waypoint);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
@@ -329,12 +351,18 @@
|
||||
const points = segment.trkpt ?? [];
|
||||
|
||||
if (points.length > 0) {
|
||||
addAnchor(points[0].$.lat!, points[0].$.lon!, false);
|
||||
addAnchor(
|
||||
points[0].$.lat!,
|
||||
points[0].$.lon!,
|
||||
anchors.length,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (i == segments.length - 1) {
|
||||
addAnchor(
|
||||
points[points.length - 1].$.lat!,
|
||||
points[points.length - 1].$.lon!,
|
||||
anchors.length,
|
||||
false,
|
||||
);
|
||||
}
|
||||
@@ -369,6 +397,7 @@
|
||||
$formData.expand!.waypoints.splice(index, 1);
|
||||
$formData.waypoints.splice(index, 1);
|
||||
$formData.expand!.waypoints = $formData.expand!.waypoints;
|
||||
// updateTrailOnMap();
|
||||
}
|
||||
|
||||
function saveWaypoint(savedWaypoint: Waypoint) {
|
||||
@@ -377,7 +406,6 @@
|
||||
);
|
||||
|
||||
if (editedWaypointIndex >= 0) {
|
||||
$formData.expand!.waypoints[editedWaypointIndex].marker?.remove();
|
||||
$formData.expand!.waypoints[editedWaypointIndex] = savedWaypoint;
|
||||
} else {
|
||||
savedWaypoint.id = cryptoRandomString({ length: 15 });
|
||||
@@ -385,11 +413,9 @@
|
||||
...$formData.expand!.waypoints,
|
||||
savedWaypoint,
|
||||
];
|
||||
}
|
||||
const marker = createMarkerFromWaypoint(savedWaypoint, moveMarker);
|
||||
|
||||
marker.addTo(map);
|
||||
savedWaypoint.marker = marker;
|
||||
// updateTrailOnMap();
|
||||
}
|
||||
}
|
||||
|
||||
function moveMarker(marker: M.Marker, wpId?: string) {
|
||||
@@ -405,6 +431,7 @@
|
||||
editableWaypoint.lat = position.lat;
|
||||
editableWaypoint.lon = position.lng;
|
||||
$formData.expand!.waypoints = [...$formData.expand!.waypoints];
|
||||
// updateTrailOnMap();
|
||||
}
|
||||
|
||||
function beforeSummitLogModalOpen() {
|
||||
@@ -493,7 +520,7 @@
|
||||
}
|
||||
const anchorCount = anchors.length;
|
||||
if (anchorCount == 0) {
|
||||
addAnchor(e.lngLat.lat, e.lngLat.lng);
|
||||
addAnchor(e.lngLat.lat, e.lngLat.lng, anchors.length);
|
||||
} else {
|
||||
const previousAnchor = anchors[anchorCount - 1];
|
||||
try {
|
||||
@@ -505,8 +532,8 @@
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
appendToRoute(routeWaypoints);
|
||||
addAnchor(e.lngLat.lat, e.lngLat.lng);
|
||||
insertIntoRoute(routeWaypoints);
|
||||
addAnchor(e.lngLat.lat, e.lngLat.lng, anchors.length);
|
||||
updateTrailWithRouteData();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -519,7 +546,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function addAnchor(lat: number, lon: number, addtoMap: boolean = true) {
|
||||
function addAnchor(
|
||||
lat: number,
|
||||
lon: number,
|
||||
index: number,
|
||||
addtoMap: boolean = true,
|
||||
) {
|
||||
const anchor: ValhallaAnchor = {
|
||||
id: cryptoRandomString({ length: 15 }),
|
||||
lat: lat,
|
||||
@@ -528,10 +560,13 @@
|
||||
const marker = createAnchorMarker(
|
||||
lat,
|
||||
lon,
|
||||
anchors.length + 1,
|
||||
index + 1,
|
||||
() => {
|
||||
removeAnchor(anchors.findIndex((a) => a.id == anchor.id));
|
||||
},
|
||||
(e) => {
|
||||
draggingMarker = true;
|
||||
},
|
||||
(_) => {
|
||||
if (!drawingActive) {
|
||||
return;
|
||||
@@ -540,13 +575,16 @@
|
||||
anchor.lat = position.lat;
|
||||
anchor.lon = position.lng;
|
||||
recalculateRoute(anchors.findIndex((a) => a.id == anchor.id));
|
||||
draggingMarker = false;
|
||||
},
|
||||
);
|
||||
if (addtoMap) {
|
||||
marker.addTo(map);
|
||||
}
|
||||
anchor.marker = marker;
|
||||
anchors.push(anchor);
|
||||
anchors.splice(index, 0, anchor);
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
function removeAnchor(anchorIndex: number) {
|
||||
@@ -583,21 +621,75 @@
|
||||
}
|
||||
let nextRouteSegment;
|
||||
let previousRouteSegment;
|
||||
if (anchorIndex < anchors.length - 1) {
|
||||
const nextAnchor = anchors[anchorIndex + 1];
|
||||
try {
|
||||
if (anchorIndex < anchors.length - 1) {
|
||||
const nextAnchor = anchors[anchorIndex + 1];
|
||||
|
||||
nextRouteSegment = await calculateRouteBetween(
|
||||
anchor.lat,
|
||||
anchor.lon,
|
||||
nextAnchor.lat,
|
||||
nextAnchor.lon,
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
nextRouteSegment = await calculateRouteBetween(
|
||||
anchor.lat,
|
||||
anchor.lon,
|
||||
nextAnchor.lat,
|
||||
nextAnchor.lon,
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
}
|
||||
if (anchorIndex > 0) {
|
||||
const previousAnchor = anchors[anchorIndex - 1];
|
||||
previousRouteSegment = await calculateRouteBetween(
|
||||
previousAnchor.lat,
|
||||
previousAnchor.lon,
|
||||
anchor.lat,
|
||||
anchor.lon,
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
}
|
||||
|
||||
if (nextRouteSegment) {
|
||||
editRoute(anchorIndex, nextRouteSegment);
|
||||
}
|
||||
if (previousRouteSegment) {
|
||||
editRoute(anchorIndex - 1, previousRouteSegment);
|
||||
}
|
||||
|
||||
updateTrailWithRouteData();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
show_toast({
|
||||
text: "Error calculating route",
|
||||
icon: "close",
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
if (anchorIndex > 0) {
|
||||
const previousAnchor = anchors[anchorIndex - 1];
|
||||
previousRouteSegment = await calculateRouteBetween(
|
||||
}
|
||||
|
||||
async function handleSegmentDragEnd(data: {
|
||||
segment: number;
|
||||
event: M.MapMouseEvent;
|
||||
}) {
|
||||
if (draggingMarker) {
|
||||
return;
|
||||
}
|
||||
const anchor = addAnchor(
|
||||
data.event.lngLat.lat,
|
||||
data.event.lngLat.lng,
|
||||
data.segment + 1,
|
||||
);
|
||||
for (let i = data.segment + 2; i < anchors.length; i++) {
|
||||
const anchor = anchors[i];
|
||||
const markerIcon = anchor.marker?.getElement();
|
||||
if (markerIcon) {
|
||||
const markerText = markerIcon.textContent ?? "0";
|
||||
const markerIndex = parseInt(markerText);
|
||||
markerIcon.textContent = markerIndex + 1 + "";
|
||||
}
|
||||
}
|
||||
const previousAnchor = anchors[data.segment];
|
||||
const nextAnchor = anchors[data.segment + 2];
|
||||
|
||||
try {
|
||||
const previousRouteSegment = await calculateRouteBetween(
|
||||
previousAnchor.lat,
|
||||
previousAnchor.lon,
|
||||
anchor.lat,
|
||||
@@ -605,14 +697,26 @@
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
const nextRouteSegment = await calculateRouteBetween(
|
||||
anchor.lat,
|
||||
anchor.lon,
|
||||
nextAnchor.lat,
|
||||
nextAnchor.lon,
|
||||
selectedModeOfTransport,
|
||||
autoRouting,
|
||||
);
|
||||
|
||||
editRoute(data.segment, previousRouteSegment);
|
||||
insertIntoRoute(nextRouteSegment, data.segment + 1);
|
||||
updateTrailWithRouteData();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
show_toast({
|
||||
text: "Error calculating route",
|
||||
icon: "close",
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
if (nextRouteSegment) {
|
||||
editRoute(anchorIndex, nextRouteSegment);
|
||||
}
|
||||
if (previousRouteSegment) {
|
||||
editRoute(anchorIndex - 1, previousRouteSegment);
|
||||
}
|
||||
updateTrailWithRouteData();
|
||||
}
|
||||
|
||||
function updateTrailWithRouteData() {
|
||||
@@ -623,10 +727,13 @@
|
||||
$formData.elevation_gain = totals.elevationGain;
|
||||
$formData.elevation_loss = totals.elevationLoss;
|
||||
$formData.expand!.gpx_data = route.toString();
|
||||
if (!$formData.id) {
|
||||
$formData.id = cryptoRandomString({ length: 15 });
|
||||
}
|
||||
}
|
||||
|
||||
function updateTrailOnMap() {
|
||||
mapTrail = [{ ...($formData as Trail) }];
|
||||
mapTrail = [$formData as Trail];
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -902,11 +1009,14 @@
|
||||
<div id="trail-map">
|
||||
<MapWithElevationMaplibre
|
||||
trails={mapTrail}
|
||||
waypoints={$formData.expand?.waypoints}
|
||||
drawing={drawingActive}
|
||||
showTerrain={true}
|
||||
onMarkerDragEnd={moveMarker}
|
||||
activeTrail={0}
|
||||
bind:map
|
||||
on:click={(e) => handleMapClick(e.detail)}
|
||||
on:segmentDragEnd={(e) => handleSegmentDragEnd(e.detail)}
|
||||
></MapWithElevationMaplibre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user