speed improvements for map (tbc)
This commit is contained in:
@@ -89,11 +89,8 @@
|
||||
$data.distance = undefined;
|
||||
return;
|
||||
}
|
||||
const gpxObject = await GPX.parse(trailData);
|
||||
if (gpxObject instanceof Error) {
|
||||
throw gpxObject;
|
||||
}
|
||||
|
||||
const gpxObject = GPX.parse(trailData);
|
||||
|
||||
const totals = gpxObject.features;
|
||||
|
||||
$data.duration = totals.duration / 1000;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
trail = (await gpx2trail(log.expand.gpx_data!)).trail;
|
||||
trail = gpx2trail(log.expand.gpx_data!).trail;
|
||||
trail.id = log.id;
|
||||
trail.expand!.gpx_data = log.expand.gpx_data;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import directionCaret from "$lib/assets/svgs/caret-right-solid.svg";
|
||||
import GPX from "$lib/models/gpx/gpx";
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import type { Waypoint } from "$lib/models/waypoint";
|
||||
import { theme } from "$lib/stores/theme_store";
|
||||
import { fetchGPX } from "$lib/stores/trail_store";
|
||||
import { findStartAndEndPoints } from "$lib/util/geojson_util";
|
||||
import { toGeoJson } from "$lib/util/gpx_util";
|
||||
import {
|
||||
createMarkerFromWaypoint,
|
||||
createPopupFromTrail,
|
||||
@@ -15,24 +15,17 @@
|
||||
import type { ElevationProfileControl } from "$lib/vendor/maplibre-elevation-profile/elevationprofile-control";
|
||||
import { FullscreenControl } from "$lib/vendor/maplibre-fullscreen/fullscreen-control";
|
||||
import MaplibreGraticule from "$lib/vendor/maplibre-graticule/maplibre-graticule";
|
||||
import {
|
||||
baseMapStyles,
|
||||
overlays,
|
||||
pois,
|
||||
} from "$lib/vendor/maplibre-layer-manager/layers";
|
||||
import { baseMapStyles } from "$lib/vendor/maplibre-layer-manager/layers";
|
||||
import { LayerManager } from "$lib/vendor/maplibre-layer-manager/maplibre-layer-manager";
|
||||
import {
|
||||
StyleSwitcherControl,
|
||||
type StyleSwitcherControlOptions,
|
||||
} from "$lib/vendor/maplibre-style-switcher/style-switcher-control";
|
||||
import { StyleSwitcherControl } from "$lib/vendor/maplibre-style-switcher/style-switcher-control";
|
||||
import type { Feature, FeatureCollection, GeoJSON } from "geojson";
|
||||
import * as M from "maplibre-gl";
|
||||
import "maplibre-gl/dist/maplibre-gl.css";
|
||||
import { onDestroy, onMount, untrack } from "svelte";
|
||||
import type { RadioItem } from "../base/radio_group.svelte";
|
||||
|
||||
interface Props {
|
||||
trails?: Trail[];
|
||||
gpx?: GPX;
|
||||
waypoints?: Waypoint[];
|
||||
markers?: M.Marker[];
|
||||
map?: M.Map | null;
|
||||
@@ -160,10 +153,10 @@
|
||||
toggleEpcTheme();
|
||||
});
|
||||
$effect(() => {
|
||||
if (drawing && map) {
|
||||
startDrawing();
|
||||
} else if (!drawing && map) {
|
||||
stopDrawing();
|
||||
if (drawing) {
|
||||
untrack(() => startDrawing());
|
||||
} else {
|
||||
untrack(() => stopDrawing());
|
||||
}
|
||||
});
|
||||
$effect(() => {
|
||||
@@ -203,9 +196,11 @@
|
||||
let cD: FeatureCollection = { type: "FeatureCollection", features: [] };
|
||||
let r: GeoJSON[] = [];
|
||||
|
||||
trails.forEach((t) => {
|
||||
if (t.expand?.gpx_data) {
|
||||
r.push(toGeoJson(t.expand.gpx_data) as GeoJSON);
|
||||
for (const t of trails) {
|
||||
if (t.expand?.gpx) {
|
||||
r.push(t.expand.gpx.toGeoJSON());
|
||||
} else if (t.expand?.gpx_data) {
|
||||
r.push(GPX.parse(t.expand.gpx_data).toGeoJSON());
|
||||
}
|
||||
if (clusterTrails && t.lat !== null && t.lon !== null) {
|
||||
cD.features.push({
|
||||
@@ -220,7 +215,7 @@
|
||||
},
|
||||
} as Feature);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return [r, cD];
|
||||
}
|
||||
@@ -653,9 +648,9 @@
|
||||
clusterPopup = createPopupFromTrail(trail);
|
||||
clusterPopup.setLngLat([trail.lon!, trail.lat!]).addTo(map);
|
||||
|
||||
const geojson = await fetchGPX(trail);
|
||||
const gpx = await fetchGPX(trail);
|
||||
|
||||
addClusterHighlightLayer(toGeoJson(geojson));
|
||||
addClusterHighlightLayer(GPX.parse(gpx).toGeoJSON());
|
||||
|
||||
clusterPopup.on("close", () => {
|
||||
unHighlightCluster(false);
|
||||
@@ -814,7 +809,7 @@
|
||||
}
|
||||
|
||||
function showWaypoints() {
|
||||
if (!map) {
|
||||
if (!map || drawing) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1030,23 +1025,23 @@
|
||||
type: "hillshade",
|
||||
});
|
||||
}
|
||||
|
||||
trails.forEach((t, i) => {
|
||||
const layerId = t.id!;
|
||||
|
||||
if (map?.getLayer(layerId)) {
|
||||
return;
|
||||
}
|
||||
addTrailLayer(t, layerId, i, data[i]);
|
||||
});
|
||||
if (
|
||||
activeTrail !== null &&
|
||||
!map?.getLayer("direction-carets")
|
||||
) {
|
||||
addCaretLayer(trails[activeTrail].id!);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
trails.forEach((t, i) => {
|
||||
const layerId = t.id!;
|
||||
|
||||
if (map?.getLayer(layerId)) {
|
||||
return;
|
||||
}
|
||||
addTrailLayer(t, layerId, i, data[i]);
|
||||
});
|
||||
if (
|
||||
activeTrail !== null &&
|
||||
trails[activeTrail] &&
|
||||
!map?.getLayer("direction-carets")
|
||||
) {
|
||||
addCaretLayer(trails[activeTrail].id!);
|
||||
}
|
||||
});
|
||||
|
||||
map.on("moveend", (e) => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import * as M from "maplibre-gl";
|
||||
|
||||
import { fromFile, toGeoJson } from "$lib/util/gpx_util";
|
||||
import GPX from "$lib/models/gpx/gpx";
|
||||
import { fromFile } from "$lib/util/gpx_util";
|
||||
import { onMount } from "svelte";
|
||||
interface Props {
|
||||
trailFile: File | undefined | null;
|
||||
@@ -76,7 +77,12 @@
|
||||
const sourceId = "trail-picker-geojson-source";
|
||||
const layerId = "trail-picker-geojson-layer";
|
||||
|
||||
const geojson = toGeoJson(trailData);
|
||||
const gpx = GPX.parse(trailData)
|
||||
if(gpx instanceof Error) {
|
||||
throw gpx;
|
||||
}
|
||||
|
||||
const geojson = gpx.toGeoJSON()
|
||||
|
||||
if (layer) {
|
||||
map.removeLayer(layerId);
|
||||
|
||||
@@ -10,6 +10,9 @@ import geohash from "ngeohash"
|
||||
import { encodePolyline } from '$lib/util/polyline_util';
|
||||
import { APIError } from '$lib/util/api_util';
|
||||
import type { ValhallaHeightResponse } from '../valhalla';
|
||||
import { bbox, splitMultiLineStringToLineStrings } from '$lib/util/geojson_util';
|
||||
import { browser } from '$app/environment';
|
||||
import xmldom from 'xmldom';
|
||||
|
||||
const defaultAttributes = {
|
||||
version: '1.1',
|
||||
@@ -210,31 +213,65 @@ export default class GPX {
|
||||
this.features = this.getTotals()
|
||||
}
|
||||
|
||||
static parse(gpxString: string): Promise<GPX | Error> {
|
||||
static parse(gpxString: string): GPX {
|
||||
const sanitizedGPX = gpxString.replace(/\sxmlns=""/g, '').replace(/<!--[\s\S]*?-->/g, '');
|
||||
|
||||
return new Promise<GPX | Error>((resolve, reject) => xml2js.parseString(sanitizedGPX, {
|
||||
explicitArray: false,
|
||||
attrValueProcessors: [(str: string) => {
|
||||
if (str.length && !isNaN(Number(str))) {
|
||||
return Number.isInteger(Number(str)) ? parseInt(String(str), 10) : parseFloat(String(str));
|
||||
return (function () {
|
||||
let data = null, error = null;
|
||||
xml2js.parseString(sanitizedGPX, {
|
||||
explicitArray: false,
|
||||
attrValueProcessors: [(str: string) => {
|
||||
if (str.length && !isNaN(Number(str))) {
|
||||
return Number.isInteger(Number(str)) ? parseInt(String(str), 10) : parseFloat(String(str));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
]
|
||||
}, async (err, xml) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
const gpx = new GPX({
|
||||
$: xml.gpx.$,
|
||||
metadata: xml.gpx.metadata,
|
||||
wpt: xml.gpx.wpt,
|
||||
rte: xml.gpx.rte,
|
||||
trk: xml.gpx.trk
|
||||
]
|
||||
}, (err, xml) => {
|
||||
error = err;
|
||||
data = new GPX({
|
||||
$: xml.gpx.$,
|
||||
metadata: xml.gpx.metadata,
|
||||
wpt: xml.gpx.wpt,
|
||||
rte: xml.gpx.rte,
|
||||
trk: xml.gpx.trk
|
||||
});
|
||||
});
|
||||
resolve(gpx)
|
||||
}));
|
||||
if (error) {
|
||||
throw error
|
||||
};
|
||||
return data;
|
||||
}()) as unknown as GPX;
|
||||
}
|
||||
|
||||
toGeoJSON(): GeoJSON.FeatureCollection {
|
||||
const features: GeoJSON.Feature[] = [];
|
||||
|
||||
if (this.wpt) {
|
||||
for (const wpt of this.wpt) {
|
||||
features.push(wpt.toGeoJSON());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.rte) {
|
||||
for (const rte of this.rte) {
|
||||
features.push(rte.toGeoJSON());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.trk) {
|
||||
for (const trk of this.trk) {
|
||||
features.push(...trk.toGeoJSON());
|
||||
}
|
||||
}
|
||||
|
||||
let geojson: GeoJSON.FeatureCollection = {
|
||||
type: "FeatureCollection",
|
||||
features
|
||||
};
|
||||
geojson.bbox = bbox(geojson)
|
||||
|
||||
return geojson
|
||||
}
|
||||
|
||||
toString(options?: xml2js.BuilderOptions) {
|
||||
|
||||
@@ -42,4 +42,24 @@ export default class Route {
|
||||
this.rtept = (object.rtept as Waypoint[]).map(rtept => new Waypoint(rtept))
|
||||
}
|
||||
}
|
||||
|
||||
toGeoJSON(): GeoJSON.Feature {
|
||||
const coordinates = (this.rtept || []).map(pt =>
|
||||
[pt.$.lon ?? 0, pt.$.lat ?? 0, pt.ele ?? 0]
|
||||
);
|
||||
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates
|
||||
},
|
||||
properties: {
|
||||
name: this.name,
|
||||
desc: this.desc,
|
||||
type: this.type,
|
||||
number: this.number
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type Track from './track';
|
||||
import Waypoint from './waypoint';
|
||||
|
||||
export default class TrackSegment {
|
||||
@@ -12,4 +13,38 @@ export default class TrackSegment {
|
||||
}
|
||||
this.extensions = object.extensions;
|
||||
}
|
||||
|
||||
toGeoJSON(
|
||||
track: Track,
|
||||
segmentId: number,
|
||||
featureId: number
|
||||
): GeoJSON.Feature {
|
||||
const coordinates = (this.trkpt || []).map(pt => [
|
||||
pt.$.lon ?? 0,
|
||||
pt.$.lat ?? 0,
|
||||
pt.ele ?? 0,
|
||||
]);
|
||||
|
||||
const times = (this.trkpt || []).map(pt => pt.time?.toISOString() ?? null);
|
||||
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates,
|
||||
},
|
||||
properties: {
|
||||
name: track.name,
|
||||
desc: track.desc,
|
||||
type: track.type,
|
||||
number: track.number,
|
||||
featureId,
|
||||
segmentId,
|
||||
coordinateProperties: {
|
||||
times
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,4 +42,16 @@ export default class Track {
|
||||
this.trkseg = object.trkseg.map(trkseg => new TrackSegment(trkseg));;
|
||||
}
|
||||
}
|
||||
toGeoJSON(): GeoJSON.Feature[] {
|
||||
const features: GeoJSON.Feature[] = [];
|
||||
|
||||
if (!this.trkseg) return features;
|
||||
|
||||
this.trkseg.forEach((segment, index) => {
|
||||
const feature = segment.toGeoJSON(this, index, features.length);
|
||||
features.push(feature);
|
||||
});
|
||||
|
||||
return features;
|
||||
}
|
||||
}
|
||||
@@ -78,4 +78,22 @@ export default class Waypoint {
|
||||
this.link = object.link.map(l => new Link(l));
|
||||
}
|
||||
}
|
||||
|
||||
toGeoJSON(): GeoJSON.Feature {
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: [this.$.lon ?? 0, this.$.lat ?? 0, this.ele ?? 0]
|
||||
},
|
||||
properties: {
|
||||
name: this.name,
|
||||
desc: this.desc,
|
||||
time: this.time?.toISOString(),
|
||||
type: this.type,
|
||||
sym: this.sym
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Actor } from "./activitypub/actor";
|
||||
import type { Category } from "./category";
|
||||
import type { Comment } from "./comment";
|
||||
import type GPX from "./gpx/gpx";
|
||||
import type { SummitLog } from "./summit_log";
|
||||
import type { Tag } from "./tag";
|
||||
import type { TrailLike } from "./trail_like";
|
||||
@@ -40,6 +41,7 @@ class Trail {
|
||||
author?: Actor
|
||||
comments_via_trail?: Comment[]
|
||||
gpx_data?: string
|
||||
gpx?: GPX
|
||||
trail_share_via_trail?: TrailShare[]
|
||||
trail_like_via_trail?: TrailLike[]
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import GPX from "$lib/models/gpx/gpx";
|
||||
import type Track from "$lib/models/gpx/track";
|
||||
import Track from "$lib/models/gpx/track";
|
||||
import TrackSegment from "$lib/models/gpx/track-segment";
|
||||
import { haversineDistance } from "$lib/models/gpx/utils";
|
||||
import Waypoint from "$lib/models/gpx/waypoint";
|
||||
@@ -11,7 +11,7 @@ import type { LngLat } from "maplibre-gl";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
const emtpyTrack: Track = { trkseg: [] }
|
||||
const emtpyTrack = new Track({ trkseg: [] })
|
||||
|
||||
class ValhallaStore {
|
||||
route: GPX = $state(new GPX({ trk: [emtpyTrack] }));
|
||||
@@ -193,8 +193,8 @@ export function reverseRoute() {
|
||||
}
|
||||
|
||||
export function resetRoute() {
|
||||
const delta = diff(valhallaStore.route, new GPX({ trk: [{ ...emtpyTrack }] }));
|
||||
const reverseDelta = diff(new GPX({ trk: [{ ...emtpyTrack }] }), valhallaStore.route);
|
||||
const delta = diff(valhallaStore.route, new GPX({ trk: [new Track({ ...emtpyTrack })] }));
|
||||
const reverseDelta = diff(new GPX({ trk: [new Track({ ...emtpyTrack })] }), valhallaStore.route);
|
||||
valhallaStore.route = applyChangeset(valhallaStore.route, delta);
|
||||
pushToUndoStack(delta, reverseDelta)
|
||||
|
||||
@@ -214,8 +214,6 @@ export async function recalculateHeight() {
|
||||
}
|
||||
|
||||
export async function splitSegment(index: number, pos: LngLat) {
|
||||
console.log(valhallaStore.route.features.duration);
|
||||
|
||||
let seg = valhallaStore.route.trk?.at(0)?.trkseg?.at(index);
|
||||
if (!seg || !seg.trkpt) {
|
||||
return;
|
||||
|
||||
@@ -18,9 +18,9 @@ import { handleFromRecordWithIRI } from "./activitypub_util";
|
||||
import { Waypoint } from "$lib/models/waypoint";
|
||||
|
||||
|
||||
export async function gpx2trail(gpxString: string, fallbackName?: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||
export function gpx2trail(gpxString: string, fallbackName?: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||
|
||||
const gpx = await GPX.parse(gpxString);
|
||||
const gpx = GPX.parse(gpxString);
|
||||
|
||||
if (gpx instanceof Error) {
|
||||
throw gpx;
|
||||
@@ -87,7 +87,7 @@ export async function trail2gpx(trail: Trail, user?: AuthRecord) {
|
||||
}
|
||||
}
|
||||
|
||||
const gpx = await GPX.parse(gpxTrail.expand!.gpx_data!) as GPX;
|
||||
const gpx = GPX.parse(gpxTrail.expand!.gpx_data!);
|
||||
|
||||
if (gpx instanceof Error) {
|
||||
throw gpx;
|
||||
@@ -108,12 +108,12 @@ export async function trail2gpx(trail: Trail, user?: AuthRecord) {
|
||||
for (const wp of gpxTrail.expand!.waypoints ?? []) {
|
||||
const gpxWpt = gpx.wpt.find((w) => w.$.lat == wp.lat && w.$.lon == wp.lon)
|
||||
if (!gpxWpt) {
|
||||
gpx.wpt.push({
|
||||
gpx.wpt.push(new GPXWaypoint({
|
||||
$: {
|
||||
lat: wp.lat,
|
||||
lon: wp.lon
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,16 +351,6 @@ function isKMZFile(buffer: ArrayBuffer) {
|
||||
return blob[0] === 0x50 && blob[1] === 0x4B && blob[2] === 0x03 && blob[3] === 0x04;
|
||||
}
|
||||
|
||||
export function toGeoJson(gpxData: string) {
|
||||
const parser = browser ? new DOMParser() : new xmldom.DOMParser();
|
||||
let geojson = gpx(
|
||||
parser.parseFromString(gpxData, "text/xml"),
|
||||
) as GeoJSON;
|
||||
geojson = splitMultiLineStringToLineStrings(geojson);
|
||||
geojson.bbox = bbox(geojson)
|
||||
return geojson
|
||||
}
|
||||
|
||||
export function cropGPX(start: GPXWaypoint, end: GPXWaypoint, gpx: GPX): GPX {
|
||||
let foundStart = false;
|
||||
let done = false;
|
||||
@@ -390,7 +380,7 @@ export function cropGPX(start: GPXWaypoint, end: GPXWaypoint, gpx: GPX): GPX {
|
||||
}
|
||||
|
||||
if (newPoints.length > 0) {
|
||||
croppedSegments.push({ trkpt: newPoints });
|
||||
croppedSegments.push(new TrackSegment({ trkpt: newPoints }));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -400,5 +390,5 @@ export function cropGPX(start: GPXWaypoint, end: GPXWaypoint, gpx: GPX): GPX {
|
||||
};
|
||||
}).filter(track => track.trkseg.length > 0);
|
||||
|
||||
return new GPX({ ...gpx, trk: croppedTrk ?? [], })
|
||||
return new GPX({ ...gpx, trk: croppedTrk?.map(t => new Track({ ...t })) ?? [], })
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export async function PUT(event: RequestEvent) {
|
||||
}
|
||||
let parseResult: { trail: Trail, gpx: GPX };
|
||||
try {
|
||||
parseResult = (await gpx2trail(gpxData, data.get("name") as string | undefined, event.fetch));
|
||||
parseResult = gpx2trail(gpxData, data.get("name") as string | undefined, event.fetch);
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
throw new ClientResponseError({ status: 400, response: { message: "Invalid file" } })
|
||||
|
||||
@@ -99,6 +99,8 @@
|
||||
import { backInOut } from "svelte/easing";
|
||||
import { fly, slide } from "svelte/transition";
|
||||
import { z } from "zod";
|
||||
import Track from "$lib/models/gpx/track.js";
|
||||
import TrackSegment from "$lib/models/gpx/track-segment.js";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -202,6 +204,7 @@
|
||||
photoFiles = [new File([blob], "route")];
|
||||
}
|
||||
|
||||
form.expand!.gpx_data = valhallaStore.route.toString();
|
||||
if (form.expand!.gpx_data && overwriteGPX) {
|
||||
gpxFile = new Blob([form.expand!.gpx_data], {
|
||||
type: "text/xml",
|
||||
@@ -267,23 +270,25 @@
|
||||
clearUndoRedoStack();
|
||||
|
||||
if ($formData.expand!.gpx_data) {
|
||||
const gpx = await GPX.parse($formData.expand!.gpx_data);
|
||||
const gpx = GPX.parse($formData.expand!.gpx_data);
|
||||
if (!(gpx instanceof Error)) {
|
||||
if (gpx.rte && !gpx.trk) {
|
||||
gpx.trk = [
|
||||
{
|
||||
new Track({
|
||||
trkseg: [
|
||||
{
|
||||
new TrackSegment({
|
||||
trkpt: gpx.rte?.at(0)?.rtept,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
}),
|
||||
];
|
||||
gpx.rte = undefined;
|
||||
}
|
||||
|
||||
setRoute(gpx);
|
||||
initRouteAnchors(gpx);
|
||||
|
||||
updateTrailOnMap();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -305,6 +310,7 @@
|
||||
clearAnchors();
|
||||
clearUndoRedoStack();
|
||||
clearRoute();
|
||||
mapTrail = [];
|
||||
drawingActive = false;
|
||||
overwriteGPX = false;
|
||||
|
||||
@@ -313,10 +319,11 @@
|
||||
|
||||
try {
|
||||
const prevId = $formData.id;
|
||||
const parseResult = await gpx2trail(gpxData, selectedFile.name);
|
||||
const parseResult = gpx2trail(gpxData, selectedFile.name);
|
||||
setFields(parseResult.trail);
|
||||
$formData.id = prevId ?? cryptoRandomString({ length: 15 });
|
||||
$formData.expand!.gpx_data = gpxData;
|
||||
|
||||
setFields(
|
||||
"category",
|
||||
page.data.settings.category || $categories[0].id,
|
||||
@@ -345,18 +352,20 @@
|
||||
|
||||
if (parseResult.gpx.rte?.length && !parseResult.gpx.trk) {
|
||||
parseResult.gpx.trk = [
|
||||
{
|
||||
new Track({
|
||||
trkseg: [
|
||||
{
|
||||
new TrackSegment({
|
||||
trkpt: parseResult.gpx.rte?.at(0)?.rtept,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
}),
|
||||
];
|
||||
parseResult.gpx.rte = undefined;
|
||||
}
|
||||
setRoute(parseResult.gpx);
|
||||
initRouteAnchors(parseResult.gpx);
|
||||
|
||||
updateTrailOnMap();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
@@ -919,7 +928,6 @@
|
||||
}
|
||||
|
||||
function toggleCropMarkers(active: boolean) {
|
||||
console.log("toggleCropMarkers", active);
|
||||
if (active) {
|
||||
cropStartMarker?.setOpacity("1");
|
||||
cropEndMarker?.setOpacity("1");
|
||||
@@ -1035,8 +1043,8 @@
|
||||
function updateTrailWithRouteData() {
|
||||
overwriteGPX = true;
|
||||
updateTotals(valhallaStore.route);
|
||||
$formData.expand!.gpx_data = valhallaStore.route.toString();
|
||||
|
||||
updateTrailOnMap();
|
||||
if (!$formData.id) {
|
||||
$formData.id = cryptoRandomString({ length: 15 });
|
||||
}
|
||||
@@ -1044,14 +1052,19 @@
|
||||
|
||||
function updateTotals(gpx: GPX) {
|
||||
const totals = gpx.features;
|
||||
$formData.distance = totals.distance;
|
||||
$formData.duration = totals.duration / 1000;
|
||||
$formData.elevation_gain = totals.elevationGain;
|
||||
$formData.elevation_loss = totals.elevationLoss;
|
||||
formData.set({
|
||||
...$formData,
|
||||
distance: totals.distance,
|
||||
duration: totals.duration / 1000,
|
||||
elevation_gain: totals.elevationGain,
|
||||
elevation_loss: totals.elevationLoss,
|
||||
});
|
||||
}
|
||||
|
||||
function updateTrailOnMap() {
|
||||
mapTrail = [$formData as Trail];
|
||||
const t = { ...$formData } as Trail;
|
||||
t.expand!.gpx = valhallaStore.route;
|
||||
mapTrail = [t];
|
||||
}
|
||||
|
||||
function handleSearchClick(item: SearchItem) {
|
||||
@@ -1071,12 +1084,6 @@
|
||||
icon: getIconForLocation(h),
|
||||
}));
|
||||
}
|
||||
let gpxData = $derived($formData.expand?.gpx_data);
|
||||
$effect(() => {
|
||||
if (gpxData) {
|
||||
untrack(() => updateTrailOnMap());
|
||||
}
|
||||
});
|
||||
|
||||
function getTrailTags() {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user