diff --git a/package-lock.json b/package-lock.json index 49e028734..3aac1a975 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,6 +69,7 @@ "katex": "0.16.21", "knockout": "3.5.1", "leaflet": "1.9.4", + "leaflet-gpx": "2.1.2", "mark.js": "8.11.1", "marked": "15.0.6", "mermaid": "11.4.1", @@ -132,6 +133,7 @@ "@types/jasmine": "5.1.5", "@types/jquery": "3.5.32", "@types/jsdom": "21.1.7", + "@types/leaflet-gpx": "1.3.7", "@types/mime-types": "2.1.4", "@types/multer": "1.4.12", "@types/node": "22.12.0", @@ -3839,6 +3841,16 @@ "@types/geojson": "*" } }, + "node_modules/@types/leaflet-gpx": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/leaflet-gpx/-/leaflet-gpx-1.3.7.tgz", + "integrity": "sha512-IDshIOLZ7dUUjRiCE3DuJcAGavgUCw0xQ93dc/3YvsA6jrFc+nx8eXr0tqZIf2SaWMgqiDj/n7N24WWNh/898g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/leaflet": "*" + } + }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -11431,6 +11443,12 @@ "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", "license": "BSD-2-Clause" }, + "node_modules/leaflet-gpx": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/leaflet-gpx/-/leaflet-gpx-2.1.2.tgz", + "integrity": "sha512-lKoEPlAWel9KXn9keg6Dmyt7gmj5IYyD8CKuxivN+77GpZr2bpKliwFvZJxLUHmNu4fICmCySyxhm5qjZuvvQg==", + "license": "BSD-2-Clause" + }, "node_modules/limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", diff --git a/package.json b/package.json index 4216a3d26..fa88fd4fd 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "katex": "0.16.21", "knockout": "3.5.1", "leaflet": "1.9.4", + "leaflet-gpx": "2.1.2", "mark.js": "8.11.1", "marked": "15.0.6", "mermaid": "11.4.1", @@ -174,6 +175,7 @@ "@types/jasmine": "5.1.5", "@types/jquery": "3.5.32", "@types/jsdom": "21.1.7", + "@types/leaflet-gpx": "1.3.7", "@types/mime-types": "2.1.4", "@types/multer": "1.4.12", "@types/node": "22.12.0", diff --git a/src/public/app/widgets/type_widgets/geo_map.ts b/src/public/app/widgets/type_widgets/geo_map.ts index 6a80ca0a5..a4b7d5707 100644 --- a/src/public/app/widgets/type_widgets/geo_map.ts +++ b/src/public/app/widgets/type_widgets/geo_map.ts @@ -104,6 +104,7 @@ export default class GeoMapTypeWidget extends TypeWidget { private _state: State; private L!: Leaflet; private currentMarkerData: MarkerData; + private gpxLoaded?: boolean; static getType() { return "geoMap"; @@ -172,6 +173,11 @@ export default class GeoMapTypeWidget extends TypeWidget { this.currentMarkerData = {}; const childNotes = await this.note.getChildNotes(); for (const childNote of childNotes) { + if (childNote.mime === "application/gpx+xml") { + this.#processNoteWithGpxTrack(childNote); + continue; + } + const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE); if (latLng) { this.#processNoteWithMarker(childNote, latLng); @@ -179,6 +185,26 @@ export default class GeoMapTypeWidget extends TypeWidget { } } + async #processNoteWithGpxTrack(note: FNote) { + if (!this.L || !this.geoMapWidget.map) { + return; + } + + if (!this.gpxLoaded) { + await import("leaflet-gpx"); + this.gpxLoaded = true; + } + + // TODO: This is not very efficient as it's probably a string response that is parsed and then converted back to string and parsed again. + const xmlResponse = await server.get(`notes/${note.noteId}/open`); + const stringResponse = new XMLSerializer().serializeToString(xmlResponse); + + const track = new this.L.GPX(stringResponse, { + + }); + track.addTo(this.geoMapWidget.map); + } + #processNoteWithMarker(note: FNote, latLng: string) { const map = this.geoMapWidget.map; if (!map) {