diff --git a/web/src/lib/components/base/double_slider.svelte b/web/src/lib/components/base/double_slider.svelte index 55c8098c..f3a9ead7 100644 --- a/web/src/lib/components/base/double_slider.svelte +++ b/web/src/lib/components/base/double_slider.svelte @@ -9,6 +9,7 @@ currentMin?: any; currentMax?: any; onset?: (data: [number, number]) => void; + onupdate?: (data: [number, number]) => void; } let { @@ -17,6 +18,7 @@ currentMin = $bindable(minValue), currentMax = $bindable(maxValue), onset, + onupdate, }: Props = $props(); let sliderContainer: any = $state(); @@ -25,6 +27,7 @@ const updateValues = (values: string[]) => { currentMin = parseFloat(values[0]); currentMax = parseFloat(values[1]); + onupdate?.([currentMin, currentMax]); }; noUiSlider.create(sliderContainer, { diff --git a/web/src/lib/components/trail/map_with_elevation_maplibre.svelte b/web/src/lib/components/trail/map_with_elevation_maplibre.svelte index 0cad2198..a5943b9d 100644 --- a/web/src/lib/components/trail/map_with_elevation_maplibre.svelte +++ b/web/src/lib/components/trail/map_with_elevation_maplibre.svelte @@ -716,6 +716,7 @@ if (!map) { return; } + hideWaypoints(); activeTrail ??= 0; map.getCanvas().style.cursor = "crosshair"; if (trails[activeTrail]) { @@ -727,6 +728,7 @@ if (!map) { return; } + showWaypoints(); map.getCanvas().style.cursor = "inherit"; if (activeTrail !== null && trails[activeTrail] && !clusterTrails) { diff --git a/web/src/lib/components/trail/route_editor.svelte b/web/src/lib/components/trail/route_editor.svelte new file mode 100644 index 00000000..e81e2abf --- /dev/null +++ b/web/src/lib/components/trail/route_editor.svelte @@ -0,0 +1,411 @@ + + +
+
+ + + +
+ + {#if editRoute} +
+ + +
+ + + +
+ {#if showSettings} +
+ {#if options.modeOfTransport === "pedestrian" && options.pedestrianOptions} +

+ {$_("walking-speed")} +

+ +

+ {formatSpeed( + options.pedestrianOptions.walking_speed! / 3.6, + )} +

+
+

{$_("use-hills")}

+ +

+ {options.pedestrianOptions.use_hills?.toFixed(2)} +

+
+

+ {$_("max-hiking-difficulty")} +

+ +

+ {options.pedestrianOptions.max_hiking_difficulty?.toFixed( + 0, + )} +

+
+ + {:else if options.modeOfTransport === "bicycle" && options.bicycleOptions} + +
+

+ {$_("cycling-speed")} +

+ +

+ {formatSpeed( + options.bicycleOptions.cycling_speed! / 3.6, + )} +

+
+

{$_("use-hills")}

+ +

+ {options.bicycleOptions.use_hills?.toFixed(2)} +

+
+

{$_("use-roads")}

+ +

+ {options.bicycleOptions.use_roads?.toFixed(2)} +

+
+

+ {$_("avoid-bad-surfaces")} +

+ +

+ {options.bicycleOptions.avoid_bad_surfaces?.toFixed( + 2, + )} +

+
+ + {:else if options.modeOfTransport === "auto" && options.autoOptions} +

+ {$_("fixed-speed")} +

+ +

+ {formatSpeed( + options.autoOptions.fixed_speed! / 3.6, + )} +

+
+

{$_("top-speed")}

+ +

+ {formatSpeed(options.autoOptions.top_speed! / 3.6)} +

+
+

+ {$_("car")} + {$_("width")} +

+ +

+ {options.autoOptions.width?.toFixed(1)} +

+
+

+ {$_("car")} + {$_("height")} +

+ +

+ {options.autoOptions.height?.toFixed(1)} +

+
+ + {/if} +
+ {/if} +
+ {/if} + + {#if crop} +
+ + + +
+ {/if} + + {#if recalculateElevationData} +
+ +

+ {$_("recalculating-elevation-data-hint")} +

+
+ {/if} +
diff --git a/web/src/lib/components/trail/routing_options_popup.svelte b/web/src/lib/components/trail/routing_options_popup.svelte deleted file mode 100644 index 356e5028..00000000 --- a/web/src/lib/components/trail/routing_options_popup.svelte +++ /dev/null @@ -1,288 +0,0 @@ - - -
- -
- - -
-
- - -
- {#if showSettings} -
- {#if options.modeOfTransport === "pedestrian" && options.pedestrianOptions} -

{$_("walking-speed")}

- -

- {formatSpeed( - options.pedestrianOptions.walking_speed! / 3.6, - )} -

-
-

{$_("use-hills")}

- -

- {options.pedestrianOptions.use_hills?.toFixed(2)} -

-
-

{$_("max-hiking-difficulty")}

- -

- {options.pedestrianOptions.max_hiking_difficulty?.toFixed( - 0, - )} -

-
- - {:else if options.modeOfTransport === "bicycle" && options.bicycleOptions} - -
-

{$_("cycling-speed")}

- -

- {formatSpeed(options.bicycleOptions.cycling_speed! / 3.6)} -

-
-

{$_("use-hills")}

- -

- {options.bicycleOptions.use_hills?.toFixed(2)} -

-
-

{$_("use-roads")}

- -

- {options.bicycleOptions.use_roads?.toFixed(2)} -

-
-

{$_("avoid-bad-surfaces")}

- -

- {options.bicycleOptions.avoid_bad_surfaces?.toFixed(2)} -

-
- - {:else if options.modeOfTransport === "auto" && options.autoOptions} -

{$_("fixed-speed")}

- -

- {formatSpeed(options.autoOptions.fixed_speed! / 3.6)} -

-
-

{$_("top-speed")}

- -

- {formatSpeed(options.autoOptions.top_speed! / 3.6)} -

-
-

{$_("car")} {$_("width")}

- -

- {options.autoOptions.width?.toFixed(1)} -

-
-

{$_("car")} {$_("height")}

- -

- {options.autoOptions.height?.toFixed(1)} -

-
- - {/if} -
- {/if} -
diff --git a/web/src/lib/i18n/locales/de.json b/web/src/lib/i18n/locales/de.json index 1b4eff37..0e96bba2 100644 --- a/web/src/lib/i18n/locales/de.json +++ b/web/src/lib/i18n/locales/de.json @@ -81,6 +81,7 @@ "create-new-list": "Neue Liste erstellen", "create-waypoint": "Wegpunkt erstellen", "creation-date": "Erstellungsdatum", + "crop": "", "cross": "Querfeldein", "current-password": "Aktuelles Passwort", "cycling": "Radfahren", @@ -235,6 +236,7 @@ "metric": "Metrisch", "moderate": "Mittel", "more": "More", + "more-route-settings": "", "mountain": "Berg", "mountain-pass": "", "must-be-at-least-n-characters-long": "Muss mindestens {n} Zeichen lang sein", @@ -313,6 +315,8 @@ "radius": "Radius", "railway-station": "", "read-more": "Mehr", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Registrieren", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Route entfernt aus", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Auf der Karte anzeigen", "shower": "", + "skiing": "", "slogan": "Speichere deine Abenteuer!", "slope": "Steigung", "someone": "Jemand", diff --git a/web/src/lib/i18n/locales/en.json b/web/src/lib/i18n/locales/en.json index 75d617d2..fa7db8c2 100644 --- a/web/src/lib/i18n/locales/en.json +++ b/web/src/lib/i18n/locales/en.json @@ -3,7 +3,7 @@ "Canoeing": "Canoeing", "Climbing": "Climbing", "Hiking": "Hiking", - "skiing": "Skiing", + "Skiing": "", "Walking": "Walking", "about": "About", "account-delete-confirm": "You are about to delete your account. All your trails will also be deleted. Do you want to proceed?", @@ -81,6 +81,7 @@ "create-new-list": "Create new list", "create-waypoint": "Create waypoint", "creation-date": "Creation date", + "crop": "Crop", "cross": "Cross", "current-password": "Current password", "cycling": "Cycling", @@ -235,6 +236,7 @@ "metric": "Metric", "moderate": "Moderate", "more": "More", + "more-route-settings": "More route settings", "mountain": "Mountain", "mountain-pass": "Mountain pass", "must-be-at-least-n-characters-long": "Must be at least {n} characters long", @@ -313,6 +315,8 @@ "radius": "Radius", "railway-station": "Railway station", "read-more": "Read more", + "recalculate-elevation-data": "Recalculate elevation data", + "recalculating-elevation-data-hint": "Recalculating elevation data will erase the existing elevation data, if any, and replace it with data from Valhalla.", "register": "Register", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Removed trail from", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Show on map", "shower": "Shower", + "skiing": "Skiing", "slogan": "Save your adventures!", "slope": "Slope", "someone": "Someone", diff --git a/web/src/lib/i18n/locales/es.json b/web/src/lib/i18n/locales/es.json index 92ac7f98..45227f79 100644 --- a/web/src/lib/i18n/locales/es.json +++ b/web/src/lib/i18n/locales/es.json @@ -81,6 +81,7 @@ "create-new-list": "Crear una nueva lista", "create-waypoint": "Crear punto de ruta", "creation-date": "Fecha de creación", + "crop": "", "cross": "Cruzar", "current-password": "Contraseña actual", "cycling": "Ciclismo", @@ -235,6 +236,7 @@ "metric": "Métrica", "moderate": "Medio", "more": "More", + "more-route-settings": "", "mountain": "Montaña", "mountain-pass": "", "must-be-at-least-n-characters-long": "Tiene que tener por lo menos {n} caracteres", @@ -313,6 +315,8 @@ "radius": "Radio", "railway-station": "", "read-more": "Leer más", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Registrar", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Ruta borrada de", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Mostrar en mapa", "shower": "", + "skiing": "", "slogan": "¡Guarda tus aventuras!", "slope": "Pendiente", "someone": "Alguien", diff --git a/web/src/lib/i18n/locales/eu.json b/web/src/lib/i18n/locales/eu.json index fcbe5609..6c7e0a55 100644 --- a/web/src/lib/i18n/locales/eu.json +++ b/web/src/lib/i18n/locales/eu.json @@ -81,6 +81,7 @@ "create-new-list": "Create new list", "create-waypoint": "Create waypoint", "creation-date": "Creation date", + "crop": "", "cross": "Cross", "current-password": "Current password", "cycling": "Cycling", @@ -235,6 +236,7 @@ "metric": "Metric", "moderate": "Moderate", "more": "More", + "more-route-settings": "", "mountain": "Mountain", "mountain-pass": "", "must-be-at-least-n-characters-long": "Must be at least {n} characters long", @@ -313,6 +315,8 @@ "radius": "Radius", "railway-station": "", "read-more": "Read more", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Register", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Removed trail from", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Show on map", "shower": "", + "skiing": "", "slogan": "Save your adventures!", "slope": "Slope", "someone": "Someone", diff --git a/web/src/lib/i18n/locales/fr.json b/web/src/lib/i18n/locales/fr.json index 185d7e67..22445d52 100644 --- a/web/src/lib/i18n/locales/fr.json +++ b/web/src/lib/i18n/locales/fr.json @@ -81,6 +81,7 @@ "create-new-list": "Créer une nouvelle liste", "create-waypoint": "Créer un point de passage", "creation-date": "Date de création", + "crop": "", "cross": "Cross", "current-password": "Mot de passe actuel", "cycling": "Vélo", @@ -235,6 +236,7 @@ "metric": "Métrique", "moderate": "Moyenne", "more": "More", + "more-route-settings": "", "mountain": "Montagne", "mountain-pass": "", "must-be-at-least-n-characters-long": "Doit être composé d'au moins {n} caractères", @@ -313,6 +315,8 @@ "radius": "Rayon", "railway-station": "", "read-more": "Voir plus", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Créer un compte", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Enlever l'itinéraire de", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Voir sur la carte", "shower": "", + "skiing": "", "slogan": "Sauvegarder vos aventures !", "slope": "Pente", "someone": "Quelqu'un", diff --git a/web/src/lib/i18n/locales/hu.json b/web/src/lib/i18n/locales/hu.json index 431dcd99..ab7a218a 100644 --- a/web/src/lib/i18n/locales/hu.json +++ b/web/src/lib/i18n/locales/hu.json @@ -81,6 +81,7 @@ "create-new-list": "Új lista létrehozása", "create-waypoint": "Create waypoint", "creation-date": "létrehozás dátuma", + "crop": "", "cross": "Cross", "current-password": "Current password", "cycling": "Cycling", @@ -235,6 +236,7 @@ "metric": "Metrikus", "moderate": "Mérsékelt", "more": "More", + "more-route-settings": "", "mountain": "Mountain", "mountain-pass": "", "must-be-at-least-n-characters-long": "Legalább {n} karakter hosszúnak kell lennie", @@ -313,6 +315,8 @@ "radius": "Átmérő", "railway-station": "", "read-more": "Read more", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Regisztráció", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Eltávolított nyomvonal a", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Mutatás térképen", "shower": "", + "skiing": "", "slogan": "Mentse el a kalandjait!", "slope": "Slope", "someone": "Someone", diff --git a/web/src/lib/i18n/locales/it.json b/web/src/lib/i18n/locales/it.json index 138ba73c..32cabe75 100644 --- a/web/src/lib/i18n/locales/it.json +++ b/web/src/lib/i18n/locales/it.json @@ -81,6 +81,7 @@ "create-new-list": "Crea nuova lista", "create-waypoint": "Create waypoint", "creation-date": "Data di creazione", + "crop": "", "cross": "Cross", "current-password": "Password attuale", "cycling": "Ciclismo", @@ -235,6 +236,7 @@ "metric": "Metrico", "moderate": "Moderato", "more": "More", + "more-route-settings": "", "mountain": "Mountain", "mountain-pass": "", "must-be-at-least-n-characters-long": "Deve essere lungo almeno {n} caratteri", @@ -313,6 +315,8 @@ "radius": "Raggio", "railway-station": "", "read-more": "Per saperne di più", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Registrati", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Percorso rimosso da", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Mostra sulla mappa", "shower": "", + "skiing": "", "slogan": "Salva le tue avventure!", "slope": "Pendenza", "someone": "Qualcuno", diff --git a/web/src/lib/i18n/locales/nl.json b/web/src/lib/i18n/locales/nl.json index ddee8941..dcf5708f 100644 --- a/web/src/lib/i18n/locales/nl.json +++ b/web/src/lib/i18n/locales/nl.json @@ -81,6 +81,7 @@ "create-new-list": "Nieuwe lijst", "create-waypoint": "Nieuw routepunt", "creation-date": "Aanmaakdatum", + "crop": "", "cross": "Oversteken", "current-password": "Huidig wachtwoord", "cycling": "Fietsen", @@ -235,6 +236,7 @@ "metric": "Metrisch", "moderate": "Gemiddeld", "more": "More", + "more-route-settings": "", "mountain": "Berg", "mountain-pass": "", "must-be-at-least-n-characters-long": "Minimaal {n} tekens", @@ -313,6 +315,8 @@ "radius": "Straal", "railway-station": "", "read-more": "Lees meer", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Registreren", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Route verwijderd van", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Tonen op kaart", "shower": "", + "skiing": "", "slogan": "Bewaar je avonturen!", "slope": "helling", "someone": "Iemand", diff --git a/web/src/lib/i18n/locales/pl.json b/web/src/lib/i18n/locales/pl.json index e10a2183..68cb17cc 100644 --- a/web/src/lib/i18n/locales/pl.json +++ b/web/src/lib/i18n/locales/pl.json @@ -81,6 +81,7 @@ "create-new-list": "Stwórz nową listę", "create-waypoint": "Utwórz punkt trasy", "creation-date": "Data dodania", + "crop": "", "cross": "Krzyż", "current-password": "Obecne hasło", "cycling": "Rower", @@ -235,6 +236,7 @@ "metric": "Metryczne", "moderate": "Średni", "more": "More", + "more-route-settings": "", "mountain": "Góra", "mountain-pass": "", "must-be-at-least-n-characters-long": "Długość musi wynosić przynajmniej {n} znaków", @@ -313,6 +315,8 @@ "radius": "Promień", "railway-station": "", "read-more": "Czytaj dalej", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Zarejestruj", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Usunięto szlak z", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Pokaż na mapie", "shower": "", + "skiing": "", "slogan": "Zapisz swoją wyprawę!", "slope": "Nachylenie", "someone": "Ktoś", diff --git a/web/src/lib/i18n/locales/pt.json b/web/src/lib/i18n/locales/pt.json index 815a7355..228472e0 100644 --- a/web/src/lib/i18n/locales/pt.json +++ b/web/src/lib/i18n/locales/pt.json @@ -81,6 +81,7 @@ "create-new-list": "Criar nova lista", "create-waypoint": "Create waypoint", "creation-date": "Data de criação", + "crop": "", "cross": "Cross", "current-password": "Senha atual", "cycling": "Ciclismo", @@ -235,6 +236,7 @@ "metric": "Métrica", "moderate": "Moderado", "more": "More", + "more-route-settings": "", "mountain": "Mountain", "mountain-pass": "", "must-be-at-least-n-characters-long": "Deve ter pelo menos {n} caracteres", @@ -313,6 +315,8 @@ "radius": "Raio", "railway-station": "", "read-more": "Ler mais", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Registo", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Trilha removida de", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Mostrar no mapa", "shower": "", + "skiing": "", "slogan": "Guarde as suas aventuras!", "slope": "Inclinação", "someone": "Someone", diff --git a/web/src/lib/i18n/locales/ru.json b/web/src/lib/i18n/locales/ru.json index 2d5f53f2..150c22ef 100644 --- a/web/src/lib/i18n/locales/ru.json +++ b/web/src/lib/i18n/locales/ru.json @@ -81,6 +81,7 @@ "create-new-list": "Создать новый список", "create-waypoint": "Создать путевую точку", "creation-date": "Дата создания", + "crop": "", "cross": "Циклокросс", "current-password": "Текущий пароль", "cycling": "Велосипед", @@ -235,6 +236,7 @@ "metric": "Метрическая", "moderate": "Средний", "more": "More", + "more-route-settings": "", "mountain": "Горный", "mountain-pass": "", "must-be-at-least-n-characters-long": "Минимум {n} символов", @@ -313,6 +315,8 @@ "radius": "Радиус", "railway-station": "", "read-more": "Подробнее", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "Регистрация", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "Трек удалён из", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "Показать на карте", "shower": "", + "skiing": "", "slogan": "Сохраняйте ваши приключения!", "slope": "Уклон", "someone": "Кто-то", diff --git a/web/src/lib/i18n/locales/zh.json b/web/src/lib/i18n/locales/zh.json index 4340b85a..ccfcf7ec 100644 --- a/web/src/lib/i18n/locales/zh.json +++ b/web/src/lib/i18n/locales/zh.json @@ -81,6 +81,7 @@ "create-new-list": "创建新列表", "create-waypoint": "Create waypoint", "creation-date": "创建日期", + "crop": "", "cross": "Cross", "current-password": "当前密码", "cycling": "骑行", @@ -235,6 +236,7 @@ "metric": "公制", "moderate": "中等", "more": "More", + "more-route-settings": "", "mountain": "Mountain", "mountain-pass": "", "must-be-at-least-n-characters-long": "长度至少 {n} 字符", @@ -313,6 +315,8 @@ "radius": "半径", "railway-station": "", "read-more": "阅读更多", + "recalculate-elevation-data": "", + "recalculating-elevation-data-hint": "", "register": "注册", "remote-users-cannot-edit": "Remote users cannot edit", "removed-trail-from": "路线已删除自", @@ -366,6 +370,7 @@ "show-less": "Show less", "show-on-map": "地图中展示", "shower": "", + "skiing": "", "slogan": "保存你的冒险!", "slope": "坡度", "someone": "Someone", diff --git a/web/src/lib/models/gpx/gpx-metrics-computation.ts b/web/src/lib/models/gpx/gpx-metrics-computation.ts index 67febfc3..86dc88ce 100644 --- a/web/src/lib/models/gpx/gpx-metrics-computation.ts +++ b/web/src/lib/models/gpx/gpx-metrics-computation.ts @@ -12,6 +12,7 @@ class GpxMetricsComputation { totalElevationLossSmoothed = 0; totalDistance = 0; totalDistanceSmoothed = 0; + cumulativeDistance: number[] = [] constructor(thresholdXY_m: number, thresholdZ_m: number) { this.thresholdXY_m = thresholdXY_m; @@ -35,6 +36,7 @@ class GpxMetricsComputation { ); this.totalDistance += distance; + this.cumulativeDistance.push(this.totalDistance) this.lastFilteredPointXY = point; diff --git a/web/src/lib/models/gpx/gpx.ts b/web/src/lib/models/gpx/gpx.ts index a62c55df..2887c304 100644 --- a/web/src/lib/models/gpx/gpx.ts +++ b/web/src/lib/models/gpx/gpx.ts @@ -25,6 +25,7 @@ type GPXFeature = { centroid: { lat: number; lon: number }; boundingBox: { minLat: number; maxLat: number; minLon: number; maxLon: number }; distance: number; + cumulativeDistance: number[] elevationGain?: number; elevationLoss?: number; duration: number; @@ -146,6 +147,7 @@ export default class GPX { centroid, boundingBox, distance: totalDistance, + cumulativeDistance: metrics.cumulativeDistance, elevationGain: totalElevationGain, elevationLoss: totalElevationLoss, duration: Math.abs(totalDuration), @@ -153,6 +155,20 @@ export default class GPX { } } + flatten() { + const points: Waypoint[] = []; + + this.trk?.forEach(track => { + track.trkseg?.forEach(segment => { + segment.trkpt?.forEach(pt => { + points.push(pt); + }); + }); + }); + + return points; + } + private generateMinHash(points: Waypoint[]): string { const hashes = points.map(pt => geohash.encode(pt.$.lat, pt.$.lon)); return hashes.sort().join('').slice(0, 10); diff --git a/web/src/lib/stores/valhalla_store.ts b/web/src/lib/stores/valhalla_store.svelte.ts similarity index 74% rename from web/src/lib/stores/valhalla_store.ts rename to web/src/lib/stores/valhalla_store.svelte.ts index eef3ecf3..4677d892 100644 --- a/web/src/lib/stores/valhalla_store.ts +++ b/web/src/lib/stores/valhalla_store.svelte.ts @@ -10,16 +10,28 @@ import { _ } from "svelte-i18n"; const emtpyTrack: Track = { trkseg: [] } -export let route: GPX = new GPX({ trk: [emtpyTrack] }); -export let anchors: ValhallaAnchor[] = []; + +class ValhallaStore { + route: GPX = $state(new GPX({ trk: [emtpyTrack] })); + anchors: ValhallaAnchor[] = $state([]); +} + +export const valhallaStore = new ValhallaStore(); + export function clearRoute() { - route = new GPX({ trk: [emtpyTrack] }); - anchors = []; + valhallaStore.route = new GPX({ trk: [emtpyTrack] }); +} + +export function clearAnchors() { + for (const anchor of valhallaStore.anchors) { + anchor.marker?.remove(); + } + valhallaStore.anchors = []; } export function setRoute(newRoute: GPX) { - route = newRoute + valhallaStore.route = newRoute } export async function calculateRouteBetween(startLat: number, startLon: number, endLat: number, endLon: number, options: RoutingOptions) { @@ -81,41 +93,41 @@ export async function insertIntoRoute(waypoints: Waypoint[], index?: number) { const segment = new TrackSegment({ trkpt: waypoints }) if (index) { - route.trk?.at(0)?.trkseg?.splice(index, 0, segment); + valhallaStore.route.trk?.at(0)?.trkseg?.splice(index, 0, segment); } else { - route.trk?.at(0)?.trkseg?.push(segment); + valhallaStore.route.trk?.at(0)?.trkseg?.push(segment); } - route.features = route.getTotals(); + valhallaStore.route.features = valhallaStore.route.getTotals(); } export async function editRoute(index: number, waypoints: Waypoint[]) { - const segment = route.trk?.at(0)?.trkseg?.at(index) + const segment = valhallaStore.route.trk?.at(0)?.trkseg?.at(index) if (segment) { segment.trkpt = waypoints } - route.features = route.getTotals(); + valhallaStore.route.features = valhallaStore.route.getTotals(); } export function deleteFromRoute(index: number) { - route.trk?.at(0)?.trkseg?.splice(index, 1); - route.features = route.getTotals(); + valhallaStore.route.trk?.at(0)?.trkseg?.splice(index, 1); + valhallaStore.route.features = valhallaStore.route.getTotals(); } export function reverseRoute() { - for (const trk of route.trk ?? []) { + for (const trk of valhallaStore.route.trk ?? []) { for (const seg of trk.trkseg ?? []) { seg.trkpt?.reverse() } trk.trkseg?.reverse() } - route.trk?.reverse() + valhallaStore.route.trk?.reverse() - route.features = route.getTotals(); + valhallaStore.route.features = valhallaStore.route.getTotals(); - anchors.reverse(); + valhallaStore.anchors.reverse(); - anchors.forEach((a, i) => { + valhallaStore.anchors.forEach((a, i) => { if (!a.marker) { return; } @@ -126,29 +138,33 @@ export function reverseRoute() { ._content.getElementsByTagName("h5")[0]; if (anchorPopupHeading) { anchorPopupHeading.textContent = - get(_)("route-point") + " #" + (i + 1); + get(_)("valhallaStore.route-point") + " #" + (i + 1); } }); } export function resetRoute() { - route = new GPX({ trk: [emtpyTrack] }); + valhallaStore.route = new GPX({ trk: [{ ...emtpyTrack }] }); - anchors.forEach((a) => { - if(!a.marker) { + valhallaStore.anchors.forEach((a) => { + if (!a.marker) { return; } a.marker.remove(); }) - anchors = [] + valhallaStore.anchors = [] +} + +export async function recalculateHeight() { + await valhallaStore.route.correctElevation(); } export function normalizeRouteTime() { let currentTime = new Date(); - for (const seg of route.trk?.at(0)?.trkseg ?? []) { + for (const seg of valhallaStore.route.trk?.at(0)?.trkseg ?? []) { if (!seg.trkpt?.length) { continue diff --git a/web/src/lib/util/gpx_util.ts b/web/src/lib/util/gpx_util.ts index e0b32f50..a54b0610 100644 --- a/web/src/lib/util/gpx_util.ts +++ b/web/src/lib/util/gpx_util.ts @@ -1,6 +1,5 @@ import GPX from "$lib/models/gpx/gpx"; import { Trail } from "$lib/models/trail"; -import { Waypoint } from "$lib/models/waypoint"; import { gpx, kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON"; import cryptoRandomString from "crypto-random-string"; //@ts-ignore @@ -16,6 +15,7 @@ import * as xmldom from 'xmldom'; import { bbox, splitMultiLineStringToLineStrings } from "./geojson_util"; import { trails_show } from "$lib/stores/trail_store"; 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 = fetch) { @@ -25,11 +25,11 @@ export async function gpx2trail(gpxString: string, fallbackName?: string, f: (ur if (gpx instanceof Error) { throw gpx; } - try { - await gpx.correctElevation(f) - } catch(e) { - console.warn("Unable to correct elevation: " + e) - } + // try { + // await gpx.correctElevation(f) + // } catch(e) { + // console.warn("Unable to correct elevation: " + e) + // } const trail = new Trail(""); @@ -86,7 +86,7 @@ export async function trail2gpx(trail: Trail, user?: AuthRecord) { gpxTrail = response; } } - + const gpx = await GPX.parse(gpxTrail.expand!.gpx_data!) as GPX; if (gpx instanceof Error) { @@ -359,4 +359,46 @@ export function toGeoJson(gpxData: string) { 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; + + const croppedTrk = gpx.trk?.map(track => { + const croppedSegments: TrackSegment[] = []; + + track.trkseg?.forEach(seg => { + const newPoints: GPXWaypoint[] = []; + + for (const pt of seg.trkpt ?? []) { + if (!foundStart) { + if (pt === start) { + foundStart = true; + newPoints.push(pt); + } + continue; + } + + if (foundStart && !done) { + newPoints.push(pt); + if (pt === end) { + done = true; + break; + } + } + } + + if (newPoints.length > 0) { + croppedSegments.push({ trkpt: newPoints }); + } + }); + + return { + ...track, + trkseg: croppedSegments, + }; + }).filter(track => track.trkseg.length > 0); + + return new GPX({ ...gpx, trk: croppedTrk ?? [], }) } \ No newline at end of file diff --git a/web/src/lib/util/maplibre_util.ts b/web/src/lib/util/maplibre_util.ts index 761f24da..53010ef5 100644 --- a/web/src/lib/util/maplibre_util.ts +++ b/web/src/lib/util/maplibre_util.ts @@ -13,9 +13,9 @@ import { formatDistance, formatElevation, formatTimeHHMM } from "./format_util"; import { icons } from "./icon_util"; export class FontawesomeMarker extends M.Marker { - constructor(options: { icon: string, fontSize?: string, width?: number, backgroundColor?: string, fontColor?: string, id?: string }, markerOptions?: M.MarkerOptions) { + constructor(options: { icon: string, fontSize?: string, width?: number, backgroundColor?: string, fontColor?: string, style?: string, id?: string }, markerOptions?: M.MarkerOptions) { const element = document.createElement('div') - element.className = `cursor-pointer flex items-center justify-center w-${options.width ?? 7} aspect-square ${options.backgroundColor ?? "bg-gray-500"} rounded-full text-${options.fontSize ?? "normal"}` + element.className = `cursor-pointer flex items-center justify-center w-${options.width ?? 7} aspect-square ${options.backgroundColor ?? "bg-gray-500"} rounded-full text-${options.fontSize ?? "normal"} ${options.style ?? ""}` element.id = options.id ?? ""; super({ element: element, ...markerOptions }); diff --git a/web/src/routes/trail/edit/[id]/+page.svelte b/web/src/routes/trail/edit/[id]/+page.svelte index adc69f6b..722bdee4 100644 --- a/web/src/routes/trail/edit/[id]/+page.svelte +++ b/web/src/routes/trail/edit/[id]/+page.svelte @@ -4,7 +4,6 @@ import Datepicker from "$lib/components/base/datepicker.svelte"; import Select from "$lib/components/base/select.svelte"; import TextField from "$lib/components/base/text_field.svelte"; - import Textarea from "$lib/components/base/textarea.svelte"; import Toggle from "$lib/components/base/toggle.svelte"; import ListSelectModal from "$lib/components/list/list_select_modal.svelte"; import SummitLogCard from "$lib/components/summit_log/summit_log_card.svelte"; @@ -17,6 +16,7 @@ import { TrailCreateSchema } from "$lib/models/api/trail_schema.js"; import { WaypointCreateSchema } from "$lib/models/api/waypoint_schema.js"; import GPX from "$lib/models/gpx/gpx"; + import GPXWaypoint from "$lib/models/gpx/waypoint"; import type { List } from "$lib/models/list"; import { SummitLog } from "$lib/models/summit_log"; import { Trail } from "$lib/models/trail"; @@ -35,26 +35,27 @@ trails_update, } from "$lib/stores/trail_store.js"; import { - anchors, + valhallaStore, calculateRouteBetween, + clearAnchors, clearRoute, deleteFromRoute, editRoute, insertIntoRoute, normalizeRouteTime, + recalculateHeight, resetRoute, reverseRoute, - route, setRoute, - } from "$lib/stores/valhalla_store"; + } from "$lib/stores/valhalla_store.svelte.js"; import { waypoint } from "$lib/stores/waypoint_store"; - import { getFileURL, readAsDataURLAsync } from "$lib/util/file_util"; + import { getFileURL } from "$lib/util/file_util"; import { formatDistance, formatElevation, formatTimeHHMM, } from "$lib/util/format_util"; - import { fromFile, gpx2trail } from "$lib/util/gpx_util"; + import { cropGPX, fromFile, gpx2trail } from "$lib/util/gpx_util"; import { page } from "$app/state"; import emptyStateTrailDark from "$lib/assets/svgs/empty_states/empty_state_trail_dark.svg"; @@ -63,10 +64,11 @@ type ComboboxItem, } from "$lib/components/base/combobox.svelte"; import type { DropdownItem } from "$lib/components/base/dropdown.svelte"; + import Editor from "$lib/components/base/editor.svelte"; import Search, { type SearchItem, } from "$lib/components/base/search.svelte"; - import RoutingOptionsPopup from "$lib/components/trail/routing_options_popup.svelte"; + import RouteEditor from "$lib/components/trail/route_editor.svelte"; import { TagCreateSchema } from "$lib/models/api/tag_schema.js"; import { convertDMSToDD } from "$lib/models/gpx/utils.js"; import { Tag } from "$lib/models/tag.js"; @@ -76,10 +78,12 @@ } from "$lib/stores/search_store.js"; import { tags_index } from "$lib/stores/tag_store.js"; import { theme } from "$lib/stores/theme_store.js"; + import { currentUser } from "$lib/stores/user_store.js"; import { getIconForLocation } from "$lib/util/icon_util.js"; import { createAnchorMarker, createEditTrailMapPopup, + FontawesomeMarker, } from "$lib/util/maplibre_util"; import EXIF from "$lib/vendor/exif-js/exif.js"; import { validator } from "@felte/validator-zod"; @@ -89,10 +93,8 @@ import { onMount, untrack } from "svelte"; import { _ } from "svelte-i18n"; import { backInOut } from "svelte/easing"; - import { scale } from "svelte/transition"; + import { slide } from "svelte/transition"; import { z } from "zod"; - import { currentUser } from "$lib/stores/user_store.js"; - import Editor from "$lib/components/base/editor.svelte"; let { data } = $props(); @@ -119,6 +121,13 @@ let searchDropdownItems: SearchItem[] = $state([]); + let cropStartMarker: FontawesomeMarker; + let cropEndMarker: FontawesomeMarker; + + let flatRoute: GPXWaypoint[] = $derived(valhallaStore.route.flatten()) + + let croppedGPX: GPX | null = null; + const ClientTrailCreateSchema = TrailCreateSchema.extend({ expand: z .object({ @@ -199,13 +208,13 @@ if ( (!form.lat || !form.lon) && - route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0) + valhallaStore.route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0) ) { - form.lat = route.trk + form.lat = valhallaStore.route.trk ?.at(0) ?.trkseg?.at(0) ?.trkpt?.at(0)?.$.lat; - form.lon = route.trk + form.lon = valhallaStore.route.trk ?.at(0) ?.trkseg?.at(0) ?.trkpt?.at(0)?.$.lon; @@ -344,6 +353,7 @@ } setRoute(parseResult.gpx); initRouteAnchors(parseResult.gpx); + initCropMarkers(); } catch (e) { console.error(e); @@ -370,12 +380,10 @@ } function clearAnchorMarker() { - for (const anchor of anchors) { - anchor.marker?.remove(); - } + clearAnchors(); } - function initRouteAnchors(gpx: GPX) { + function initRouteAnchors(gpx: GPX, addToMap: boolean = false) { const segments = gpx.trk?.at(0)?.trkseg ?? []; for (let i = 0; i < segments.length; i++) { @@ -386,21 +394,67 @@ addAnchor( points[0].$.lat!, points[0].$.lon!, - anchors.length, - false, + valhallaStore.anchors.length, + addToMap, ); } if (i == segments.length - 1) { addAnchor( points[points.length - 1].$.lat!, points[points.length - 1].$.lon!, - anchors.length, - false, + valhallaStore.anchors.length, + addToMap, ); } } } + function initCropMarkers() { + const routeStartPoint: M.LngLatLike = [ + valhallaStore.route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0)?.$.lon ?? 0, + valhallaStore.route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0)?.$.lat ?? 0, + ]; + const routeEndPoint: M.LngLatLike = [ + valhallaStore.route.trk?.at(-1)?.trkseg?.at(-1)?.trkpt?.at(-1)?.$.lon ?? 0, + valhallaStore.route.trk?.at(-1)?.trkseg?.at(-1)?.trkpt?.at(-1)?.$.lat ?? 0, + ]; + if (!cropStartMarker || !cropEndMarker) { + cropStartMarker = new FontawesomeMarker( + { + id: "crop-start-marker", + icon: "fa-regular fa-circle", + fontSize: "xs", + style: "z-10", + width: 4, + backgroundColor: "bg-primary", + fontColor: "white", + }, + {}, + ); + cropEndMarker = new FontawesomeMarker( + { + id: "crop-end-marker", + icon: "fa fa-flag-checkered", + fontSize: "xs", + style: "z-10", + width: 4, + backgroundColor: "bg-primary", + fontColor: "white", + }, + {}, + ); + + cropStartMarker + .setOpacity("0") + .setLngLat(routeStartPoint) + .addTo(map!); + cropEndMarker.setOpacity("0").setLngLat(routeEndPoint).addTo(map!); + } else { + cropStartMarker.setLngLat(routeStartPoint); + cropEndMarker.setLngLat(routeEndPoint); + } + } + function openMarkerPopup(waypoint: Waypoint) { waypoint.marker?.togglePopup(); } @@ -545,25 +599,25 @@ return; } drawingActive = true; - if (!route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.length) { + if (!valhallaStore.route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.length) { } - for (const anchor of anchors) { + for (const anchor of valhallaStore.anchors) { anchor.marker?.addTo(map); } } async function stopDrawing() { drawingActive = false; - for (const anchor of anchors) { + for (const anchor of valhallaStore.anchors) { anchor.marker?.remove(); } - if (route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0)) { - $formData.lat = route.trk + if (valhallaStore.route.trk?.at(0)?.trkseg?.at(0)?.trkpt?.at(0)) { + $formData.lat = valhallaStore.route.trk ?.at(0) ?.trkseg?.at(0) ?.trkpt?.at(0)?.$.lat; - $formData.lon = route.trk + $formData.lon = valhallaStore.route.trk ?.at(0) ?.trkseg?.at(0) ?.trkpt?.at(0)?.$.lon; @@ -593,9 +647,9 @@ }); mapPopup.addTo(map!); } else { - const anchorCount = anchors.length; + const anchorCount = valhallaStore.anchors.length; if (anchorCount == 0) { - addAnchor(e.lngLat.lat, e.lngLat.lng, anchors.length); + addAnchor(e.lngLat.lat, e.lngLat.lng, valhallaStore.anchors.length); } else { await addAnchorAndRecalculate(e.lngLat.lat, e.lngLat.lng); } @@ -603,8 +657,8 @@ } async function addAnchorAndRecalculate(lat: number, lon: number) { - const previousAnchor = anchors[anchors.length - 1]; - const anchor = addAnchor(lat, lon, anchors.length); + const previousAnchor = valhallaStore.anchors[valhallaStore.anchors.length - 1]; + const anchor = addAnchor(lat, lon, valhallaStore.anchors.length); const markerText = startAnchorLoading(anchor); try { const routeWaypoints = await calculateRouteBetween( @@ -645,10 +699,10 @@ lon, index + 1, () => { - removeAnchor(anchors.findIndex((a) => a.id == anchor.id)); + removeAnchor(valhallaStore.anchors.findIndex((a) => a.id == anchor.id)); }, () => { - const thisAnchor = anchors.find((a) => a.id == anchor.id); + const thisAnchor = valhallaStore.anchors.find((a) => a.id == anchor.id); addAnchorAndRecalculate( thisAnchor?.lat ?? lat, thisAnchor?.lon ?? lon, @@ -666,7 +720,7 @@ anchor.lat = position.lat; anchor.lon = position.lng; await recalculateRoute( - anchors.findIndex((a) => a.id == anchor.id), + valhallaStore.anchors.findIndex((a) => a.id == anchor.id), ); draggingMarker = false; }, @@ -675,7 +729,7 @@ marker.addTo(map); } anchor.marker = marker; - anchors.splice(index, 0, anchor); + valhallaStore.anchors.splice(index, 0, anchor); return anchor; } @@ -709,10 +763,10 @@ if (!drawingActive) { return; } - anchors[anchorIndex]?.marker?.remove(); - anchors.splice(anchorIndex, 1); - for (let i = anchorIndex; i < anchors.length; i++) { - const anchor = anchors[i]; + valhallaStore.anchors[anchorIndex]?.marker?.remove(); + valhallaStore.anchors.splice(anchorIndex, 1); + for (let i = anchorIndex; i < valhallaStore.anchors.length; i++) { + const anchor = valhallaStore.anchors[i]; const markerIcon = anchor.marker?.getElement(); if (markerIcon) { const markerText = markerIcon.textContent ?? "0"; @@ -730,7 +784,7 @@ if ($formData.expand?.gpx_data) { updateTrailWithRouteData(); } - } else if (anchorIndex == anchors.length) { + } else if (anchorIndex == valhallaStore.anchors.length) { deleteFromRoute(anchorIndex - 1); updateTrailWithRouteData(); } else { @@ -740,17 +794,17 @@ } async function recalculateRoute(anchorIndex: number) { - const markerText = startAnchorLoading(anchors[anchorIndex]); + const markerText = startAnchorLoading(valhallaStore.anchors[anchorIndex]); - const anchor = anchors[anchorIndex]; + const anchor = valhallaStore.anchors[anchorIndex]; if (!anchor) { return; } let nextRouteSegment; let previousRouteSegment; try { - if (anchorIndex < anchors.length - 1) { - const nextAnchor = anchors[anchorIndex + 1]; + if (anchorIndex < valhallaStore.anchors.length - 1) { + const nextAnchor = valhallaStore.anchors[anchorIndex + 1]; nextRouteSegment = await calculateRouteBetween( anchor.lat, @@ -761,7 +815,7 @@ ); } if (anchorIndex > 0) { - const previousAnchor = anchors[anchorIndex - 1]; + const previousAnchor = valhallaStore.anchors[anchorIndex - 1]; previousRouteSegment = await calculateRouteBetween( previousAnchor.lat, previousAnchor.lon, @@ -789,7 +843,7 @@ type: "error", }); } finally { - stopAnchorLoading(anchors[anchorIndex], markerText); + stopAnchorLoading(valhallaStore.anchors[anchorIndex], markerText); } } @@ -807,8 +861,8 @@ ); const markerText = startAnchorLoading(anchor); - for (let i = data.segment + 2; i < anchors.length; i++) { - const anchor = anchors[i]; + for (let i = data.segment + 2; i < valhallaStore.anchors.length; i++) { + const anchor = valhallaStore.anchors[i]; const markerIcon = anchor.marker?.getElement(); if (markerIcon) { const markerText = markerIcon.textContent ?? "0"; @@ -821,8 +875,8 @@ $_("route-point") + " #" + newIndex; } } - const previousAnchor = anchors[data.segment]; - const nextAnchor = anchors[data.segment + 2]; + const previousAnchor = valhallaStore.anchors[data.segment]; + const nextAnchor = valhallaStore.anchors[data.segment + 2]; try { const previousRouteSegment = await calculateRouteBetween( @@ -864,18 +918,101 @@ function resetTrail() { resetRoute(); - + updateTrailWithRouteData(); } - function updateTrailWithRouteData() { - overwriteGPX = true; - const totals = route.features; + async function recalculateElevationData() { + await recalculateHeight(); + + updateTrailWithRouteData(); + } + + function toggleCropMarkers(active: boolean) { + if (active) { + cropStartMarker?.setOpacity("1"); + cropEndMarker?.setOpacity("1"); + } else { + cropStartMarker?.setOpacity("0"); + cropEndMarker?.setOpacity("0"); + } + } + + function updateCropMarkers(range: [start: number, end: number]) { + const [start, end] = range; + + const targetStartDistance = valhallaStore.route.features.distance * (start / 100); + const [startLon, startLat, startIndex] = getCoordinateAtDistance( + flatRoute, + valhallaStore.route.features.cumulativeDistance, + targetStartDistance, + ); + + const targetEndDistance = valhallaStore.route.features.distance * (end / 100); + const [endLon, endLat, endIndex] = getCoordinateAtDistance( + flatRoute, + valhallaStore.route.features.cumulativeDistance, + targetEndDistance, + ); + + cropStartMarker.setLngLat([startLon, startLat]); + cropEndMarker.setLngLat([endLon, endLat]); + + croppedGPX = cropGPX(flatRoute[startIndex], flatRoute[endIndex], valhallaStore.route); + const totals = croppedGPX.features; $formData.distance = totals.distance; $formData.duration = totals.duration / 1000; $formData.elevation_gain = totals.elevationGain; $formData.elevation_loss = totals.elevationLoss; - $formData.expand!.gpx_data = route.toString(); + } + + function confirmCrop() { + if (!croppedGPX) { + return; + } + setRoute(croppedGPX); + updateTrailWithRouteData(); + clearAnchorMarker(); + initRouteAnchors(croppedGPX, true); + } + + function getCoordinateAtDistance( + points: GPXWaypoint[], + cumulative: number[], + target: number, + ) { + let low = 0, + high = cumulative.length - 1; + + while (low < high) { + const mid = Math.floor((low + high) / 2); + if (cumulative[mid] < target) low = mid + 1; + else high = mid; + } + + const i = Math.max(1, low); + const prevDist = cumulative[i - 1]; + const nextDist = cumulative[i]; + const ratio = (target - prevDist) / (nextDist - prevDist); + + const prev = points[i - 1]; + const next = points[i]; + + return [ + prev.$.lon! + (next.$.lon! - prev.$.lon!) * ratio, + prev.$.lat! + (next.$.lat! - prev.$.lat!) * ratio, + i, + ]; + } + + function updateTrailWithRouteData() { + overwriteGPX = true; + const totals = valhallaStore.route.features; + $formData.distance = totals.distance; + $formData.duration = totals.duration / 1000; + $formData.elevation_gain = totals.elevationGain; + $formData.elevation_loss = totals.elevationLoss; + $formData.expand!.gpx_data = valhallaStore.route.toString(); if (!$formData.id) { $formData.id = cryptoRandomString({ length: 15 }); @@ -1288,15 +1425,19 @@
{#if drawingActive}
- + onCropToggle={toggleCropMarkers} + onCrop={confirmCrop} + onUpdateCropRange={updateCropMarkers} + onRecalculateElevationData={recalculateElevationData} + >
{/if}
diff --git a/web/vite.config.ts b/web/vite.config.ts index 325ab66e..91ed557e 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -9,12 +9,12 @@ export default defineConfig({ ssr: { noExternal: ['three'] }, ...(process.env.WANDERER_ENV == "dev" ? { server: { - https: { - key: fs.readFileSync('.svelte-kit/key.pem'), - cert: fs.readFileSync('.svelte-kit/cert.pem') - }, - host: true, // true - port: 443 // 443 + // https: { + // key: fs.readFileSync('.svelte-kit/key.pem'), + // cert: fs.readFileSync('.svelte-kit/cert.pem') + // }, + // host: true, // true + // port: 443 // 443 } } : {}) });