adds trail export
This commit is contained in:
80
web/package-lock.json
generated
80
web/package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"isomorphic-xml2js": "^0.1.3",
|
||||
"jspdf": "^2.5.1",
|
||||
"jszip": "^3.10.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-gpx": "^1.7.0",
|
||||
"leaflet.awesome-markers": "^2.0.5",
|
||||
@@ -1884,6 +1885,11 @@
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
@@ -2879,6 +2885,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
@@ -3442,6 +3453,22 @@
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/jszip": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||
"dependencies": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"setimmediate": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip/node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
@@ -3465,6 +3492,14 @@
|
||||
"resolved": "https://registry.npmjs.org/leaflet.awesome-markers/-/leaflet.awesome-markers-2.0.5.tgz",
|
||||
"integrity": "sha512-Ne/xDjkGyaujwNVVkv2tyXQUV0ZW7gZ0Mo0FuQY4jp2qWrvXi0hwDBvmZyF/8YOvybyMabTMM/mFWCTd1jZIQA=="
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||
@@ -4394,6 +4429,11 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"node_modules/property-expr": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
|
||||
@@ -4486,6 +4526,25 @@
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@@ -4682,6 +4741,11 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
@@ -4761,6 +4825,11 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -4884,6 +4953,14 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
@@ -5611,8 +5688,7 @@
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"isomorphic-xml2js": "^0.1.3",
|
||||
"jspdf": "^2.5.1",
|
||||
"jszip": "^3.10.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-gpx": "^1.7.0",
|
||||
"leaflet.awesome-markers": "^2.0.5",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { User } from '$lib/models/user'
|
||||
import { pb } from '$lib/pocketbase'
|
||||
import { settings_show } from '$lib/stores/settings_store';
|
||||
import { currentUser } from '$lib/stores/user_store'
|
||||
import { get } from 'svelte/store';
|
||||
import type { User } from '$lib/models/user';
|
||||
import { pb } from '$lib/pocketbase';
|
||||
import { currentUser } from '$lib/stores/user_store';
|
||||
|
||||
pb.authStore.loadFromCookie(document.cookie)
|
||||
pb.authStore.onChange(() => {
|
||||
|
||||
@@ -9,17 +9,22 @@
|
||||
} from "$lib/stores/list_store";
|
||||
import { show_toast } from "$lib/stores/toast_store";
|
||||
import { trails_delete } from "$lib/stores/trail_store";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { trail2gpx } from "$lib/util/gpx_util";
|
||||
import { gpx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import { _ } from "svelte-i18n";
|
||||
import Dropdown, { type DropdownItem } from "../base/dropdown.svelte";
|
||||
import ConfirmModal from "../confirm_modal.svelte";
|
||||
import ListSelectModal from "../list/list_select_modal.svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
import TrailExportModal from "./trail_export_modal.svelte";
|
||||
import JSZip from "jszip";
|
||||
import { getFileURL, saveAs } from "$lib/util/file_util";
|
||||
|
||||
export let trail: Trail;
|
||||
export let mode: "overview" | "map";
|
||||
|
||||
let openConfirmModal: () => void;
|
||||
let openListSelectModal: () => void;
|
||||
let openExportModal: () => void;
|
||||
|
||||
const dropdownItems: DropdownItem[] = [
|
||||
mode == "overview"
|
||||
@@ -34,7 +39,7 @@
|
||||
...(trail.gpx
|
||||
? [
|
||||
{
|
||||
text: $_("download-gpx"),
|
||||
text: $_("export"),
|
||||
value: "download",
|
||||
icon: "download",
|
||||
},
|
||||
@@ -65,7 +70,7 @@
|
||||
} else if (item.value == "print") {
|
||||
goto(`/map/trail/${trail.id}/print`);
|
||||
} else if (item.value == "download") {
|
||||
downloadURI(getFileURL(trail, trail.gpx), trail.gpx!);
|
||||
openExportModal();
|
||||
} else if (item.value == "edit") {
|
||||
goto(`/trail/edit/${trail.id}`);
|
||||
} else if (item.value == "delete") {
|
||||
@@ -73,13 +78,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
function downloadURI(uri: string, name: string) {
|
||||
var link = document.createElement("a");
|
||||
link.setAttribute("download", name);
|
||||
link.href = uri;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
async function exportTrail(exportSettings: {
|
||||
fileFormat: "gpx" | "json";
|
||||
photos: boolean;
|
||||
summitLog: boolean;
|
||||
}) {
|
||||
try {
|
||||
let fileData: string = await trail2gpx(trail);
|
||||
if (exportSettings.fileFormat == "json") {
|
||||
fileData = JSON.stringify(gpx(new DOMParser().parseFromString(fileData, "text/xml")));
|
||||
}
|
||||
const zip = new JSZip();
|
||||
zip.file(`${trail.name}.${exportSettings.fileFormat}`, fileData);
|
||||
if (exportSettings.photos) {
|
||||
const photoFolder = zip.folder($_("photos"));
|
||||
for (const photo of trail.photos) {
|
||||
const photoURL = getFileURL(trail, photo);
|
||||
const photoBlob = await fetch(photoURL).then((response) =>
|
||||
response.blob(),
|
||||
);
|
||||
const photoData = new File([photoBlob], photo);
|
||||
photoFolder?.file(photo, photoData, { base64: true });
|
||||
}
|
||||
}
|
||||
if(exportSettings.summitLog) {
|
||||
let summitLogString = ""
|
||||
for (const summitLog of trail.expand.summit_logs) {
|
||||
summitLogString += `${summitLog.date},${summitLog.text}\n`
|
||||
}
|
||||
zip.file(`${trail.name} - ${$_("summit-book")}.csv`, summitLogString)
|
||||
}
|
||||
const blob = await zip.generateAsync({ type: "blob" });
|
||||
saveAs(blob, `${trail.name}.zip`);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
show_toast({
|
||||
type: "error",
|
||||
icon: "close",
|
||||
text: $_("error-exporting-trail"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTrail() {
|
||||
@@ -137,3 +175,7 @@
|
||||
bind:openModal={openListSelectModal}
|
||||
on:change={(e) => handleListSelection(e.detail)}
|
||||
></ListSelectModal>
|
||||
<TrailExportModal
|
||||
bind:openModal={openExportModal}
|
||||
on:export={(e) => exportTrail(e.detail)}
|
||||
></TrailExportModal>
|
||||
|
||||
80
web/src/lib/components/trail/trail_export_modal.svelte
Normal file
80
web/src/lib/components/trail/trail_export_modal.svelte
Normal file
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import Modal from "$lib/components/base/modal.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
import Select from "../base/select.svelte";
|
||||
|
||||
export let openModal: (() => void) | undefined = undefined;
|
||||
export let closeModal: (() => void) | undefined = undefined;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
||||
const fileFormats = [
|
||||
{ text: "GPX", value: "gpx" },
|
||||
{ text: "GeoJSON", value: "json" },
|
||||
];
|
||||
|
||||
const exportSettings = {
|
||||
fileFormat: "gpx",
|
||||
photos: false,
|
||||
summitLog: false,
|
||||
};
|
||||
|
||||
|
||||
function exportTrail() {
|
||||
dispatch("export", exportSettings);
|
||||
closeModal!();
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
id="export-modal"
|
||||
title="Export trail"
|
||||
size="max-w-sm"
|
||||
bind:openModal
|
||||
bind:closeModal
|
||||
>
|
||||
<div slot="content">
|
||||
<div class="mb-3">
|
||||
<Select
|
||||
bind:value={exportSettings.fileFormat}
|
||||
items={fileFormats}
|
||||
label={$_("file-format")}
|
||||
></Select>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<input
|
||||
id="include-photos-checkbox"
|
||||
type="checkbox"
|
||||
bind:checked={exportSettings.photos}
|
||||
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
|
||||
/>
|
||||
<label for="include-photos-checkbox" class="ms-2 text-sm"
|
||||
>{$_("photos")}</label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<input
|
||||
id="include-summit-log-checkbox"
|
||||
type="checkbox"
|
||||
bind:checked={exportSettings.summitLog}
|
||||
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
|
||||
/>
|
||||
<label for="include-summit-log-checkbox" class="ms-2 text-sm"
|
||||
>{$_("summit-book")}</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="flex items-center gap-4">
|
||||
<button class="btn-secondary" on:click={closeModal}
|
||||
>{$_("cancel")}</button
|
||||
>
|
||||
<button
|
||||
class="btn-primary"
|
||||
type="button"
|
||||
on:click={exportTrail}
|
||||
name="save">{$_("export")}</button
|
||||
>
|
||||
</div></Modal
|
||||
>
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Eintrag",
|
||||
"error-creating-user": "Fehler beim Erstellen des Nutzers",
|
||||
"error-during-login": "Fehler beim Login",
|
||||
"error-exporting-trail": "Fehler beim Exportieren des Trails",
|
||||
"error-printing-map": "Fehler beim Drucken der Karte",
|
||||
"error-reading-file": "Fehler beim Lesen der Datei",
|
||||
"est-duration": "Gesch. Dauer",
|
||||
"explore": "Erkunden",
|
||||
"explore-some-trails": "Erkunden Sie einige Routen",
|
||||
"export": "Exportieren",
|
||||
"features": "Features",
|
||||
"file-format": "Dateiformat",
|
||||
"french": "Französisch",
|
||||
"german": "Deutsch",
|
||||
"grid": "Gitter",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Entry",
|
||||
"error-creating-user": "Error creating user",
|
||||
"error-during-login": "Error during login",
|
||||
"error-exporting-trail": "Error exporting trail",
|
||||
"error-printing-map": "Error printing map",
|
||||
"error-reading-file": "Error reading file",
|
||||
"est-duration": "Est. duration",
|
||||
"explore": "Explore",
|
||||
"explore-some-trails": "Explore some trails",
|
||||
"export": "Export",
|
||||
"features": "Features",
|
||||
"file-format": "File format",
|
||||
"french": "French",
|
||||
"german": "German",
|
||||
"grid": "Grid",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Entrée",
|
||||
"error-creating-user": "Erreur durant la création de l'utilisateur",
|
||||
"error-during-login": "Erreur durant la connexion",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "Erreur d'impression de la carte",
|
||||
"error-reading-file": "Erreur de lecture du fichier",
|
||||
"est-duration": "Temps estimé",
|
||||
"explore": "Explorer",
|
||||
"explore-some-trails": "Explorer certains itinéraires",
|
||||
"export": "",
|
||||
"features": "Fonctionnalités",
|
||||
"file-format": "",
|
||||
"french": "Français",
|
||||
"german": "Allemand",
|
||||
"grid": "Grille",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Bejegyzés",
|
||||
"error-creating-user": "Hiba felhasználó hozzáadása közben",
|
||||
"error-during-login": "Hiba bejelentkezés közben",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "",
|
||||
"error-reading-file": "Hiba a fájl olvasása közben",
|
||||
"est-duration": "Becsült időtartam",
|
||||
"explore": "Felfedezés",
|
||||
"explore-some-trails": "Fedezzen fel néhány ösvényt",
|
||||
"export": "",
|
||||
"features": "Jellemzők",
|
||||
"file-format": "",
|
||||
"french": "Francia",
|
||||
"german": "Német",
|
||||
"grid": "",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Item",
|
||||
"error-creating-user": "Het account kan niet worden aangemaakt",
|
||||
"error-during-login": "Het inloggen is mislukt",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "Fout bij afdrukken van kaart",
|
||||
"error-reading-file": "Het bestand kan niet worden ingelezen",
|
||||
"est-duration": "Geschatte duur",
|
||||
"explore": "Verkennen",
|
||||
"explore-some-trails": "Verken enkele wandelroutes",
|
||||
"export": "",
|
||||
"features": "Kenmerken",
|
||||
"file-format": "",
|
||||
"french": "Frans",
|
||||
"german": "Duits",
|
||||
"grid": "Rooster",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Pozycja",
|
||||
"error-creating-user": "Błąd tworzenia użytkownika",
|
||||
"error-during-login": "Błąd podczas logowania",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "",
|
||||
"error-reading-file": "Błąd wczytywania pliku",
|
||||
"est-duration": "Szacowany czas",
|
||||
"explore": "Eksploruj",
|
||||
"explore-some-trails": "Eksploruj różne ścieżki",
|
||||
"export": "",
|
||||
"features": "Funkcje",
|
||||
"file-format": "",
|
||||
"french": "Francuski",
|
||||
"german": "Niemiecki",
|
||||
"grid": "",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "Entrada",
|
||||
"error-creating-user": "Erro ao criar usuário",
|
||||
"error-during-login": "Erro durante o login",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "",
|
||||
"error-reading-file": "Erro ao ler o arquivo",
|
||||
"est-duration": "Duração prevista",
|
||||
"explore": "Explorar",
|
||||
"explore-some-trails": "Explore algumas trilhas",
|
||||
"export": "",
|
||||
"features": "Características",
|
||||
"file-format": "",
|
||||
"french": "Francês",
|
||||
"german": "Alemão",
|
||||
"grid": "",
|
||||
|
||||
@@ -55,12 +55,15 @@
|
||||
"entry": "日程",
|
||||
"error-creating-user": "创建用户错误",
|
||||
"error-during-login": "登录错误",
|
||||
"error-exporting-trail": "",
|
||||
"error-printing-map": "",
|
||||
"error-reading-file": "读取文件错误",
|
||||
"est-duration": "预计时长",
|
||||
"explore": "探索",
|
||||
"explore-some-trails": "探索行程",
|
||||
"export": "",
|
||||
"features": "特性",
|
||||
"file-format": "",
|
||||
"french": "法语",
|
||||
"german": "德语",
|
||||
"grid": "",
|
||||
|
||||
@@ -8,7 +8,7 @@ export default class Metadata {
|
||||
desc: string;
|
||||
time: Date;
|
||||
keywords: string;
|
||||
extensions: string;
|
||||
extensions?: string;
|
||||
author?: Person;
|
||||
link?: Link[];
|
||||
bounds?: Bounds;
|
||||
@@ -18,7 +18,7 @@ export default class Metadata {
|
||||
desc: string,
|
||||
time: string,
|
||||
keywords: string,
|
||||
extensions: string,
|
||||
extensions?: string,
|
||||
author?: Person,
|
||||
link?: Link | Link[],
|
||||
bounds?: Bounds,
|
||||
|
||||
@@ -61,7 +61,7 @@ class Trail {
|
||||
this.id = params?.id;
|
||||
this.name = name;
|
||||
this.location = params?.location;
|
||||
this.date = params?.date;
|
||||
this.date = params?.date ?? new Date().toISOString().split('T')[0];
|
||||
this.public = params?.public ?? false
|
||||
this.distance = params?.distance;
|
||||
this.elevation_gain = params?.elevation_gain;
|
||||
|
||||
@@ -17,3 +17,14 @@ export function readAsDataURLAsync(file: File) {
|
||||
fr.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
export function saveAs(data: Blob, fileName: string) {
|
||||
var a = document.createElement("a") as HTMLAnchorElement;
|
||||
a.setAttribute("style", "display: none");
|
||||
document.body.appendChild(a);
|
||||
const url = window.URL.createObjectURL(data);
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
@@ -1,9 +1,11 @@
|
||||
import GPX from "$lib/models/gpx/gpx";
|
||||
import { Trail } from "$lib/models/trail";
|
||||
import { Waypoint } from "$lib/models/waypoint";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import GeoJsonToGpx from "$lib/vendor/geoJSONToGPX";
|
||||
import { kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import cryptoRandomString from "crypto-random-string";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
export async function gpx2trail(gpxString: string) {
|
||||
const gpx = await GPX.parse(gpxString);
|
||||
@@ -52,6 +54,43 @@ export async function gpx2trail(gpxString: string) {
|
||||
return { gpx: gpx, trail: trail }
|
||||
}
|
||||
|
||||
export async function trail2gpx(trail: Trail) {
|
||||
if (!trail.expand.gpx_data) {
|
||||
throw Error("Trail has no GPX data")
|
||||
}
|
||||
const gpx = await GPX.parse(trail.expand.gpx_data) as GPX;
|
||||
|
||||
if (gpx instanceof Error) {
|
||||
throw gpx;
|
||||
}
|
||||
|
||||
gpx.metadata = {
|
||||
name: trail.name,
|
||||
desc: trail.description ?? "",
|
||||
time: trail.date ? new Date(trail.date) : new Date(),
|
||||
keywords: `${trail.category ?? ""}, ${trail.location ?? ""}`,
|
||||
author: { name: trail.author ?? "", email: get(currentUser)?.email ?? "" }
|
||||
}
|
||||
|
||||
if(!gpx.wpt) {
|
||||
gpx.wpt = [];
|
||||
}
|
||||
|
||||
for (const wp of trail.expand.waypoints) {
|
||||
const gpxWpt = gpx.wpt.find((w) => w.$.lat == wp.lat && w.$.lon == wp.lon)
|
||||
if(!gpxWpt) {
|
||||
gpx.wpt.push({
|
||||
$: {
|
||||
lat: wp.lat,
|
||||
lon: wp.lon
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return gpx.toString();
|
||||
}
|
||||
|
||||
export function fromKML(kmlData: string) {
|
||||
const geojson = kml(new DOMParser().parseFromString(kmlData, "text/xml"))
|
||||
const options = {
|
||||
|
||||
@@ -101,9 +101,9 @@
|
||||
});
|
||||
|
||||
const modesOfTransport = [
|
||||
{ text: $_('hiking'), value: "pedestrian" },
|
||||
{ text: $_('cycling'), value: "bicycle" },
|
||||
{ text: $_('driving'), value: "auto" },
|
||||
{ text: $_("hiking"), value: "pedestrian" },
|
||||
{ text: $_("cycling"), value: "bicycle" },
|
||||
{ text: $_("driving"), value: "auto" },
|
||||
];
|
||||
let selectedModeOfTransport = modesOfTransport[0].value;
|
||||
|
||||
@@ -385,6 +385,11 @@
|
||||
savedWaypoint.marker = marker;
|
||||
}
|
||||
|
||||
function beforSummitLogModalOpen() {
|
||||
summitLog.set(new SummitLog(new Date().toISOString().split('T')[0]));
|
||||
openSummitLogModal();
|
||||
}
|
||||
|
||||
function saveSummitLog(e: CustomEvent<SummitLog>) {
|
||||
const savedSummitLog = e.detail;
|
||||
let editedSummitLogIndex = $form.expand.summit_logs.findIndex(
|
||||
@@ -791,7 +796,7 @@
|
||||
<button
|
||||
class="btn-secondary"
|
||||
type="button"
|
||||
on:click={openSummitLogModal}
|
||||
on:click={beforSummitLogModalOpen}
|
||||
><i class="fa fa-plus mr-2"></i>{$_("add-entry")}</button
|
||||
>
|
||||
{#if $lists.length}
|
||||
@@ -846,7 +851,10 @@
|
||||
>
|
||||
<Toggle bind:value={autoRouting} label="Enable auto-routing"
|
||||
></Toggle>
|
||||
<Select items={modesOfTransport} bind:value={selectedModeOfTransport} disabled={!autoRouting}
|
||||
<Select
|
||||
items={modesOfTransport}
|
||||
bind:value={selectedModeOfTransport}
|
||||
disabled={!autoRouting}
|
||||
></Select>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user