mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-04-21 19:11:17 +00:00
Compare commits
28 Commits
maplibre
...
02efe708c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02efe708c2 | ||
|
|
7dc834f506 | ||
|
|
57c4958ff2 | ||
|
|
03e59a8cce | ||
|
|
f3d18f09a0 | ||
|
|
c1dbd984e6 | ||
|
|
e4f227221d | ||
|
|
34139974aa | ||
|
|
408b2422e6 | ||
|
|
b59cb9e200 | ||
|
|
bd5cb65d0f | ||
|
|
4cfe487af0 | ||
|
|
4da2e39e32 | ||
|
|
5ff11a32c9 | ||
|
|
01a7ec916e | ||
|
|
dd94a7d613 | ||
|
|
089b88c62d | ||
|
|
9c6e03f4a8 | ||
|
|
2a4dfe010e | ||
|
|
f42a916c25 | ||
|
|
772b810fa8 | ||
|
|
4d4d10d5c2 | ||
|
|
0e4c7dbe64 | ||
|
|
a01ca79a82 | ||
|
|
c91baf7c83 | ||
|
|
5062de8ddf | ||
|
|
9ca46b9d35 | ||
|
|
7c2e24bbc4 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
|||||||
ko_fi: gpxstudio
|
open_collective: gpxstudio
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ This project has been made possible thanks to the following open source projects
|
|||||||
- [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) — fast GPX file parsing
|
- [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) — fast GPX file parsing
|
||||||
- [SortableJS](https://github.com/SortableJS/Sortable) — creating a sortable file tree
|
- [SortableJS](https://github.com/SortableJS/Sortable) — creating a sortable file tree
|
||||||
- Mapping:
|
- Mapping:
|
||||||
- [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) — beautiful and fast interactive maps
|
- [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) — beautiful and fast interactive map rendering
|
||||||
- [brouter](https://github.com/abrensch/brouter) — routing engine
|
- [GraphHopper](https://github.com/graphhopper/graphhopper) — routing engine
|
||||||
- [OpenStreetMap](https://www.openstreetmap.org) — map data used by most of the map layers, and by the routing engine
|
- [OpenStreetMap](https://www.openstreetmap.org) — map data used by most of the map layers, and by the routing engine
|
||||||
- Search:
|
- Search:
|
||||||
- [DocSearch](https://github.com/algolia/docsearch) — search engine for the documentation
|
- [DocSearch](https://github.com/algolia/docsearch) — search engine for the documentation
|
||||||
|
|||||||
@@ -1398,10 +1398,7 @@ export class TrackPoint {
|
|||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
setExtensions(extensions: Record<string, string>) {
|
setExtension(key: string, value: string) {
|
||||||
if (Object.keys(extensions).length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.extensions) {
|
if (!this.extensions) {
|
||||||
this.extensions = {};
|
this.extensions = {};
|
||||||
}
|
}
|
||||||
@@ -1411,8 +1408,12 @@ export class TrackPoint {
|
|||||||
if (!this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions']) {
|
if (!this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions']) {
|
||||||
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'] = {};
|
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'] = {};
|
||||||
}
|
}
|
||||||
Object.entries(extensions).forEach(([key, value]) => {
|
|
||||||
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'][key] = value;
|
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'][key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
setExtensions(extensions: Record<string, string>) {
|
||||||
|
Object.entries(extensions).forEach(([key, value]) => {
|
||||||
|
this.setExtension(key, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
109
website/package-lock.json
generated
109
website/package-lock.json
generated
@@ -22,7 +22,7 @@
|
|||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"mapillary-js": "^4.1.2",
|
"mapillary-js": "^4.1.2",
|
||||||
"maplibre-gl": "^5.16.0",
|
"maplibre-gl": "^5.21.1",
|
||||||
"sanitize-html": "^2.17.0",
|
"sanitize-html": "^2.17.0",
|
||||||
"sortablejs": "^1.15.6",
|
"sortablejs": "^1.15.6",
|
||||||
"tailwind-merge": "^3.3.0"
|
"tailwind-merge": "^3.3.0"
|
||||||
@@ -1611,31 +1611,6 @@
|
|||||||
"svelte": "^5"
|
"svelte": "^5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/geojson-rewind": {
|
|
||||||
"version": "0.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz",
|
|
||||||
"integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"get-stream": "^6.0.1",
|
|
||||||
"minimist": "^1.2.6"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"geojson-rewind": "geojson-rewind"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@mapbox/geojson-rewind/node_modules/get-stream": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
|
||||||
@@ -1670,7 +1645,8 @@
|
|||||||
"node_modules/@mapbox/unitbezier": {
|
"node_modules/@mapbox/unitbezier": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
|
||||||
"integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="
|
"integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/vector-tile": {
|
"node_modules/@mapbox/vector-tile": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
@@ -1704,10 +1680,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/geojson-vt": {
|
"node_modules/@maplibre/geojson-vt": {
|
||||||
"version": "5.0.4",
|
"version": "6.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.0.4.tgz",
|
||||||
"integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==",
|
"integrity": "sha512-HYv3POhMRCdhP3UPPATM/hfcy6/WuVIf5FKboH8u/ZuFMTnAIcSVlq5nfOqroLokd925w2QtE7YwquFOIacwVQ==",
|
||||||
"license": "ISC"
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"kdbush": "^4.0.2"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/maplibre-gl-geocoder": {
|
"node_modules/@maplibre/maplibre-gl-geocoder": {
|
||||||
"version": "1.9.4",
|
"version": "1.9.4",
|
||||||
@@ -1729,9 +1708,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||||
"version": "24.4.1",
|
"version": "24.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.7.0.tgz",
|
||||||
"integrity": "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==",
|
"integrity": "sha512-Ed7rcKYU5iELfablg9Mj+TVCsXsPBgdMyXPRAxb2v7oWg9YJnpQdZ5msDs1LESu/mtXy3Z48Vdppv2t/x5kAhw==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||||
@@ -1749,18 +1728,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/mlt": {
|
"node_modules/@maplibre/mlt": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.8.tgz",
|
||||||
"integrity": "sha512-SQKdJ909VGROkA6ovJgtHNs9YXV4YXUPS+VaZ50I2Mt951SLlUm2Cv34x5Xwc1HiFlsd3h2Yrs5cn7xzqBmENw==",
|
"integrity": "sha512-8vtfYGidr1rNkv5IwIoU2lfe3Oy+Wa8HluzQYcQi9cveU9K3pweAal/poQj4GJ0K/EW4bTQp2wVAs09g2yDRZg==",
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"license": "(MIT OR Apache-2.0)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/point-geometry": "^1.1.0"
|
"@mapbox/point-geometry": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/vt-pbf": {
|
"node_modules/@maplibre/vt-pbf": {
|
||||||
"version": "4.2.1",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.0.tgz",
|
||||||
"integrity": "sha512-IxZBGq/+9cqf2qdWlFuQ+ZfoMhWpxDUGQZ/poPHOJBvwMUT1GuxLo6HgYTou+xxtsOsjfbcjI8PZaPCtmt97rA==",
|
"integrity": "sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/point-geometry": "^1.1.0",
|
"@mapbox/point-geometry": "^1.1.0",
|
||||||
@@ -1772,6 +1751,12 @@
|
|||||||
"supercluster": "^8.0.1"
|
"supercluster": "^8.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@maplibre/vt-pbf/node_modules/@maplibre/geojson-vt": {
|
||||||
|
"version": "5.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz",
|
||||||
|
"integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/@maplibre/vt-pbf/node_modules/pbf": {
|
"node_modules/@maplibre/vt-pbf/node_modules/pbf": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz",
|
||||||
@@ -2606,15 +2591,6 @@
|
|||||||
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
|
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/geojson-vt": {
|
|
||||||
"version": "3.2.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz",
|
|
||||||
"integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/geojson": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/hammerjs": {
|
"node_modules/@types/hammerjs": {
|
||||||
"version": "2.0.46",
|
"version": "2.0.46",
|
||||||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
|
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
|
||||||
@@ -2702,6 +2678,7 @@
|
|||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz",
|
||||||
"integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
|
"integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/geojson": "*"
|
"@types/geojson": "*"
|
||||||
}
|
}
|
||||||
@@ -4605,12 +4582,6 @@
|
|||||||
"node": ">= 0.6.0"
|
"node": ">= 0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/geojson-vt": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
@@ -5282,7 +5253,8 @@
|
|||||||
"node_modules/kdbush": {
|
"node_modules/kdbush": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
|
||||||
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="
|
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==",
|
||||||
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
@@ -5683,33 +5655,29 @@
|
|||||||
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
|
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
|
||||||
},
|
},
|
||||||
"node_modules/maplibre-gl": {
|
"node_modules/maplibre-gl": {
|
||||||
"version": "5.16.0",
|
"version": "5.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.21.1.tgz",
|
||||||
"integrity": "sha512-/VDY89nr4jgLJyzmhy325cG6VUI02WkZ/UfVuDbG/piXzo6ODnM+omDFIwWY8tsEsBG26DNDmNMn3Y2ikHsBiA==",
|
"integrity": "sha512-zto1RTnFkOpOO1bm93ElCXF1huey2N4LvXaGLMFcYAu9txh0OhGIdX1q3LZLkrMKgMxMeYduaQo+DVNzg098fg==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/geojson-rewind": "^0.5.2",
|
|
||||||
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
|
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
|
||||||
"@mapbox/point-geometry": "^1.1.0",
|
"@mapbox/point-geometry": "^1.1.0",
|
||||||
"@mapbox/tiny-sdf": "^2.0.7",
|
"@mapbox/tiny-sdf": "^2.0.7",
|
||||||
"@mapbox/unitbezier": "^0.0.1",
|
"@mapbox/unitbezier": "^0.0.1",
|
||||||
"@mapbox/vector-tile": "^2.0.4",
|
"@mapbox/vector-tile": "^2.0.4",
|
||||||
"@mapbox/whoots-js": "^3.1.0",
|
"@mapbox/whoots-js": "^3.1.0",
|
||||||
"@maplibre/maplibre-gl-style-spec": "^24.4.1",
|
"@maplibre/geojson-vt": "^6.0.4",
|
||||||
"@maplibre/mlt": "^1.1.2",
|
"@maplibre/maplibre-gl-style-spec": "^24.7.0",
|
||||||
"@maplibre/vt-pbf": "^4.2.0",
|
"@maplibre/mlt": "^1.1.8",
|
||||||
|
"@maplibre/vt-pbf": "^4.3.0",
|
||||||
"@types/geojson": "^7946.0.16",
|
"@types/geojson": "^7946.0.16",
|
||||||
"@types/geojson-vt": "3.2.5",
|
|
||||||
"@types/supercluster": "^7.1.3",
|
|
||||||
"earcut": "^3.0.2",
|
"earcut": "^3.0.2",
|
||||||
"geojson-vt": "^4.0.2",
|
|
||||||
"gl-matrix": "^3.4.4",
|
"gl-matrix": "^3.4.4",
|
||||||
"kdbush": "^4.0.2",
|
"kdbush": "^4.0.2",
|
||||||
"murmurhash-js": "^1.0.0",
|
"murmurhash-js": "^1.0.0",
|
||||||
"pbf": "^4.0.1",
|
"pbf": "^4.0.1",
|
||||||
"potpack": "^2.1.0",
|
"potpack": "^2.1.0",
|
||||||
"quickselect": "^3.0.0",
|
"quickselect": "^3.0.0",
|
||||||
"supercluster": "^8.0.1",
|
|
||||||
"tinyqueue": "^3.0.0"
|
"tinyqueue": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6627,7 +6595,8 @@
|
|||||||
"node_modules/quickselect": {
|
"node_modules/quickselect": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
||||||
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
|
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
|
||||||
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/randombytes": {
|
"node_modules/randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
@@ -7356,6 +7325,7 @@
|
|||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
|
||||||
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
|
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"kdbush": "^4.0.2"
|
"kdbush": "^4.0.2"
|
||||||
}
|
}
|
||||||
@@ -7814,7 +7784,8 @@
|
|||||||
"node_modules/tinyqueue": {
|
"node_modules/tinyqueue": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
|
||||||
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
|
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==",
|
||||||
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"mapillary-js": "^4.1.2",
|
"mapillary-js": "^4.1.2",
|
||||||
"maplibre-gl": "^5.16.0",
|
"maplibre-gl": "^5.21.1",
|
||||||
"sanitize-html": "^2.17.0",
|
"sanitize-html": "^2.17.0",
|
||||||
"sortablejs": "^1.15.6",
|
"sortablejs": "^1.15.6",
|
||||||
"tailwind-merge": "^3.3.0"
|
"tailwind-merge": "^3.3.0"
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import bikerouterGravel from './custom/bikerouter-gravel.json';
|
|||||||
export const maptilerKeyPlaceHolder = 'MAPTILER_KEY';
|
export const maptilerKeyPlaceHolder = 'MAPTILER_KEY';
|
||||||
|
|
||||||
export const basemaps: { [key: string]: string | StyleSpecification } = {
|
export const basemaps: { [key: string]: string | StyleSpecification } = {
|
||||||
|
maptilerStreets: `https://api.maptiler.com/maps/streets-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
||||||
maptilerTopo: `https://api.maptiler.com/maps/topo-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
maptilerTopo: `https://api.maptiler.com/maps/topo-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
||||||
maptilerOutdoors: `https://api.maptiler.com/maps/outdoor-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
maptilerOutdoors: `https://api.maptiler.com/maps/outdoor-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
||||||
maptilerSatellite: `https://api.maptiler.com/maps/hybrid-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
maptilerSatellite: `https://api.maptiler.com/maps/hybrid-v4/style.json?key=${maptilerKeyPlaceHolder}`,
|
||||||
@@ -776,6 +777,7 @@ export type LayerTreeType = { [key: string]: LayerTreeType | boolean };
|
|||||||
export const basemapTree: LayerTreeType = {
|
export const basemapTree: LayerTreeType = {
|
||||||
basemaps: {
|
basemaps: {
|
||||||
world: {
|
world: {
|
||||||
|
maptilerStreets: true,
|
||||||
maptilerTopo: true,
|
maptilerTopo: true,
|
||||||
maptilerOutdoors: true,
|
maptilerOutdoors: true,
|
||||||
maptilerSatellite: true,
|
maptilerSatellite: true,
|
||||||
@@ -911,7 +913,7 @@ export const overpassTree: LayerTreeType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Default basemap used
|
// Default basemap used
|
||||||
export const defaultBasemap = 'maptilerTopo';
|
export const defaultBasemap = 'maptilerStreets';
|
||||||
|
|
||||||
// Default overlays used (none)
|
// Default overlays used (none)
|
||||||
export const defaultOverlays: LayerTreeType = {
|
export const defaultOverlays: LayerTreeType = {
|
||||||
@@ -1000,6 +1002,7 @@ export const defaultOverpassQueries: LayerTreeType = {
|
|||||||
export const defaultBasemapTree: LayerTreeType = {
|
export const defaultBasemapTree: LayerTreeType = {
|
||||||
basemaps: {
|
basemaps: {
|
||||||
world: {
|
world: {
|
||||||
|
maptilerStreets: true,
|
||||||
maptilerTopo: true,
|
maptilerTopo: true,
|
||||||
maptilerOutdoors: true,
|
maptilerOutdoors: true,
|
||||||
maptilerSatellite: true,
|
maptilerSatellite: true,
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
class="h-6 px-0 has-[>svg]:px-0 text-muted-foreground"
|
class="h-6 px-0 has-[>svg]:px-0 text-muted-foreground"
|
||||||
href="https://ko-fi.com/gpxstudio"
|
href="https://opencollective.com/gpxstudio"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Heart size="16" />
|
<Heart size="16" />
|
||||||
|
|||||||
@@ -375,7 +375,7 @@
|
|||||||
<Menubar.Item inset onclick={() => map.toggle3D()}>
|
<Menubar.Item inset onclick={() => map.toggle3D()}>
|
||||||
<Box size="16" />
|
<Box size="16" />
|
||||||
{i18n._('menu.toggle_3d')}
|
{i18n._('menu.toggle_3d')}
|
||||||
<Shortcut key="{i18n._('menu.ctrl')} {i18n._('menu.drag')}" />
|
<Shortcut key={i18n._('menu.right_click_drag')} />
|
||||||
</Menubar.Item>
|
</Menubar.Item>
|
||||||
</Menubar.Content>
|
</Menubar.Content>
|
||||||
</Menubar.Menu>
|
</Menubar.Menu>
|
||||||
@@ -515,7 +515,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
href="https://ko-fi.com/gpxstudio"
|
href="https://opencollective.com/gpxstudio"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="cursor-default h-fit rounded-sm font-bold text-support hover:text-support px-3 py-0.5"
|
class="cursor-default h-fit rounded-sm font-bold text-support hover:text-support px-3 py-0.5"
|
||||||
aria-label={i18n._('menu.donate')}
|
aria-label={i18n._('menu.donate')}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<canvas bind:this={overlay} class="w-full h-full absolute pointer-events-none"></canvas>
|
<canvas bind:this={overlay} class="w-full h-full absolute pointer-events-none"></canvas>
|
||||||
<canvas bind:this={canvas} class="w-full h-full absolute"></canvas>
|
<canvas bind:this={canvas} class="w-full h-full absolute"></canvas>
|
||||||
{#if showControls}
|
{#if showControls}
|
||||||
<div class="absolute bottom-10 right-1.5">
|
<div class="absolute bottom-9 right-2.5">
|
||||||
<Popover.Root>
|
<Popover.Root>
|
||||||
<Popover.Trigger>
|
<Popover.Trigger>
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const defaultEmbeddingOptions = {
|
|||||||
key: '',
|
key: '',
|
||||||
files: [],
|
files: [],
|
||||||
ids: [],
|
ids: [],
|
||||||
basemap: 'maptilerTopo',
|
basemap: 'maptilerStreets',
|
||||||
elevation: {
|
elevation: {
|
||||||
show: true,
|
show: true,
|
||||||
height: 170,
|
height: 170,
|
||||||
|
|||||||
@@ -100,7 +100,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex flex-row flex-wrap gap-2">
|
<div class="w-full flex flex-row flex-wrap gap-2">
|
||||||
<Button class="bg-support grow" href="https://ko-fi.com/gpxstudio" target="_blank">
|
<Button
|
||||||
|
class="bg-support grow"
|
||||||
|
href="https://opencollective.com/gpxstudio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
{i18n._('menu.support_button')}
|
{i18n._('menu.support_button')}
|
||||||
<span>🙏</span>
|
<span>🙏</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { get } from 'svelte/store';
|
|||||||
import { map } from '$lib/components/map/map';
|
import { map } from '$lib/components/map/map';
|
||||||
import { allHidden } from '$lib/logic/hidden';
|
import { allHidden } from '$lib/logic/hidden';
|
||||||
import type { GeoJSONSource } from 'maplibre-gl';
|
import type { GeoJSONSource } from 'maplibre-gl';
|
||||||
import { ANCHOR_LAYER_KEY } from '../style';
|
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||||
|
|
||||||
const { distanceMarkers, distanceUnits } = settings;
|
const { distanceMarkers, distanceUnits } = settings;
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { fileActions } from '$lib/logic/file-actions';
|
|||||||
import { splitAs } from '$lib/components/toolbar/tools/scissors/scissors';
|
import { splitAs } from '$lib/components/toolbar/tools/scissors/scissors';
|
||||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||||
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||||
import { gpxColors } from './gpx-layers';
|
import { gpxColors } from '$lib/components/map/gpx-layer/gpx-layers';
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
'#ff0000',
|
'#ff0000',
|
||||||
@@ -251,7 +251,7 @@ export class GPXLayer {
|
|||||||
source: this.fileId,
|
source: this.fileId,
|
||||||
layout: {
|
layout: {
|
||||||
'text-field': '»',
|
'text-field': '»',
|
||||||
'text-offset': [0, -0.1],
|
'text-offset': [0, -0.06],
|
||||||
'text-keep-upright': false,
|
'text-keep-upright': false,
|
||||||
'text-max-angle': 361,
|
'text-max-angle': 361,
|
||||||
'text-allow-overlap': true,
|
'text-allow-overlap': true,
|
||||||
@@ -261,7 +261,6 @@ export class GPXLayer {
|
|||||||
},
|
},
|
||||||
paint: {
|
paint: {
|
||||||
'text-color': 'white',
|
'text-color': 'white',
|
||||||
'text-opacity': 0.7,
|
|
||||||
'text-halo-width': 0.2,
|
'text-halo-width': 0.2,
|
||||||
'text-halo-color': 'white',
|
'text-halo-color': 'white',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class StartEndMarkers {
|
|||||||
unsubscribes: (() => void)[] = [];
|
unsubscribes: (() => void)[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
map.onLoad(() => this.update());
|
map.onLoad((map_) => map_.on('style.load', this.updateBinded));
|
||||||
this.unsubscribes.push(gpxStatistics.subscribe(this.updateBinded));
|
this.unsubscribes.push(gpxStatistics.subscribe(this.updateBinded));
|
||||||
this.unsubscribes.push(slicedGPXStatistics.subscribe(this.updateBinded));
|
this.unsubscribes.push(slicedGPXStatistics.subscribe(this.updateBinded));
|
||||||
this.unsubscribes.push(hoveredPoint.subscribe(this.updateBinded));
|
this.unsubscribes.push(hoveredPoint.subscribe(this.updateBinded));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MapPopup } from '$lib/components/map/map-popup';
|
|||||||
import { settings } from '$lib/logic/settings';
|
import { settings } from '$lib/logic/settings';
|
||||||
import { db } from '$lib/db';
|
import { db } from '$lib/db';
|
||||||
import type { GeoJSONSource } from 'maplibre-gl';
|
import type { GeoJSONSource } from 'maplibre-gl';
|
||||||
import { ANCHOR_LAYER_KEY } from '../style';
|
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||||
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
||||||
import { loadSVGIcon } from '$lib/utils';
|
import { loadSVGIcon } from '$lib/utils';
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ liveQuery(() => db.overpassdata.toArray()).subscribe((pois) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export class OverpassLayer {
|
export class OverpassLayer {
|
||||||
overpassUrl = 'https://maps.mail.ru/osm/tools/overpass/api/interpreter';
|
overpassUrl = 'https://overpass.private.coffee/api/interpreter';
|
||||||
minZoom = 12;
|
minZoom = 12;
|
||||||
queryZoom = 12;
|
queryZoom = 12;
|
||||||
expirationTime = 7 * 24 * 3600 * 1000;
|
expirationTime = 7 * 24 * 3600 * 1000;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import maplibregl, { type LayerSpecification, type VectorSourceSpecification } f
|
|||||||
import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
|
import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
|
||||||
import 'mapillary-js/dist/mapillary.css';
|
import 'mapillary-js/dist/mapillary.css';
|
||||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||||
import { ANCHOR_LAYER_KEY } from '../style';
|
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||||
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
||||||
|
|
||||||
const mapillarySource: VectorSourceSpecification = {
|
const mapillarySource: VectorSourceSpecification = {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export class RoutingControls {
|
|||||||
fileUnsubscribe: () => void = () => {};
|
fileUnsubscribe: () => void = () => {};
|
||||||
unsubscribes: Function[] = [];
|
unsubscribes: Function[] = [];
|
||||||
|
|
||||||
|
updateControlsBinded: () => void = this.updateControls.bind(this);
|
||||||
appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this);
|
appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this);
|
||||||
|
|
||||||
draggedAnchorIndex: number | null = null;
|
draggedAnchorIndex: number | null = null;
|
||||||
@@ -129,10 +130,11 @@ export class RoutingControls {
|
|||||||
|
|
||||||
this.loadIcons();
|
this.loadIcons();
|
||||||
|
|
||||||
|
map_.on('style.load', this.updateControlsBinded);
|
||||||
map_.on('click', this.appendAnchorBinded);
|
map_.on('click', this.appendAnchorBinded);
|
||||||
layerEventManager.on('mousemove', this.fileId, this.showTemporaryAnchorBinded);
|
layerEventManager.on('mousemove', this.fileId, this.showTemporaryAnchorBinded);
|
||||||
|
|
||||||
this.fileUnsubscribe = this.file.subscribe(this.updateControls.bind(this));
|
this.fileUnsubscribe = this.file.subscribe(this.updateControlsBinded);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateControls() {
|
updateControls() {
|
||||||
@@ -232,6 +234,7 @@ export class RoutingControls {
|
|||||||
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
||||||
|
map_?.off('style.load', this.updateControlsBinded);
|
||||||
map_?.off('click', this.appendAnchorBinded);
|
map_?.off('click', this.appendAnchorBinded);
|
||||||
layerEventManager?.off('mousemove', this.fileId, this.showTemporaryAnchorBinded);
|
layerEventManager?.off('mousemove', this.fileId, this.showTemporaryAnchorBinded);
|
||||||
map_?.off('mousemove', this.updateTemporaryAnchorBinded);
|
map_?.off('mousemove', this.updateTemporaryAnchorBinded);
|
||||||
@@ -683,17 +686,7 @@ export class RoutingControls {
|
|||||||
try {
|
try {
|
||||||
response = await route(targetTrackPoints.map((trkpt) => trkpt.getCoordinates()));
|
response = await route(targetTrackPoints.map((trkpt) => trkpt.getCoordinates()));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.message.includes('from-position not mapped in existing datafile')) {
|
toast.error(i18n._(e.message, e.message));
|
||||||
toast.error(i18n._('toolbar.routing.error.from'));
|
|
||||||
} else if (e.message.includes('via1-position not mapped in existing datafile')) {
|
|
||||||
toast.error(i18n._('toolbar.routing.error.via'));
|
|
||||||
} else if (e.message.includes('to-position not mapped in existing datafile')) {
|
|
||||||
toast.error(i18n._('toolbar.routing.error.to'));
|
|
||||||
} else if (e.message.includes('Time-out')) {
|
|
||||||
toast.error(i18n._('toolbar.routing.error.timeout'));
|
|
||||||
} else {
|
|
||||||
toast.error(e.message);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,37 +6,213 @@ import { get } from 'svelte/store';
|
|||||||
|
|
||||||
const { routing, routingProfile, privateRoads } = settings;
|
const { routing, routingProfile, privateRoads } = settings;
|
||||||
|
|
||||||
export const routingProfiles: { [key: string]: string } = {
|
export type RoutingProfile = {
|
||||||
bike: 'Trekking-dry',
|
engine: 'graphhopper' | 'brouter';
|
||||||
racing_bike: 'fastbike',
|
profile: string;
|
||||||
gravel_bike: 'gravel',
|
};
|
||||||
mountain_bike: 'MTB',
|
|
||||||
foot: 'Hiking-Alpine-SAC6',
|
export const routingProfiles: { [key: string]: RoutingProfile } = {
|
||||||
motorcycle: 'Car-FastEco',
|
bike: { engine: 'graphhopper', profile: 'bike' },
|
||||||
water: 'river',
|
racing_bike: { engine: 'graphhopper', profile: 'racingbike' },
|
||||||
railway: 'rail',
|
gravel_bike: { engine: 'graphhopper', profile: 'gravelbike' },
|
||||||
|
mountain_bike: { engine: 'graphhopper', profile: 'mtb' },
|
||||||
|
foot: { engine: 'graphhopper', profile: 'foot' },
|
||||||
|
motorcycle: { engine: 'graphhopper', profile: 'motorcycle' },
|
||||||
|
water: { engine: 'brouter', profile: 'river' },
|
||||||
|
railway: { engine: 'brouter', profile: 'rail' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function route(points: Coordinates[]): Promise<TrackPoint[]> {
|
export function route(points: Coordinates[]): Promise<TrackPoint[]> {
|
||||||
if (get(routing)) {
|
if (get(routing)) {
|
||||||
return getRoute(points, routingProfiles[get(routingProfile)], get(privateRoads));
|
const profile = routingProfiles[get(routingProfile)];
|
||||||
|
if (profile.engine === 'graphhopper') {
|
||||||
|
return getGraphHopperRoute(points, profile.profile, get(privateRoads));
|
||||||
|
} else {
|
||||||
|
return getBRouterRoute(points, profile.profile);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return getIntermediatePoints(points);
|
return getIntermediatePoints(points);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getRoute(
|
const graphhopperDetails = ['road_class', 'surface', 'hike_rating', 'mtb_rating'];
|
||||||
|
const hikeRatingToSACScale: { [key: string]: string } = {
|
||||||
|
'1': 'hiking',
|
||||||
|
'2': 'mountain_hiking',
|
||||||
|
'3': 'demanding_mountain_hiking',
|
||||||
|
'4': 'alpine_hiking',
|
||||||
|
'5': 'demanding_alpine_hiking',
|
||||||
|
'6': 'difficult_alpine_hiking',
|
||||||
|
};
|
||||||
|
const mtbRatingToScale: { [key: string]: string } = {
|
||||||
|
'1': '0',
|
||||||
|
'2': '1',
|
||||||
|
'3': '2',
|
||||||
|
'4': '3',
|
||||||
|
'5': '4',
|
||||||
|
'6': '5',
|
||||||
|
'7': '6',
|
||||||
|
};
|
||||||
|
|
||||||
|
const graphhopperBlockPrivateCustomModels: { [key: string]: any } = {
|
||||||
|
bike: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'bike_road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
racingbike: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'bike_road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
gravelbike: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'bike_road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
mtb: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'bike_road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
foot: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'foot_road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
motorcycle: {
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
if: 'road_access == PRIVATE',
|
||||||
|
multiply_by: '0.0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
async function getGraphHopperRoute(
|
||||||
points: Coordinates[],
|
points: Coordinates[],
|
||||||
brouterProfile: string,
|
graphHopperProfile: string,
|
||||||
privateRoads: boolean
|
privateRoads: boolean
|
||||||
): Promise<TrackPoint[]> {
|
): Promise<TrackPoint[]> {
|
||||||
let url = `https://brouter.gpx.studio?lonlats=${points.map((point) => `${point.lon.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile + (privateRoads ? '-private' : '')}&format=geojson&alternativeidx=0`;
|
let response = await fetch('https://graphhopper.gpx.studio/route', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
points: points.map((point) => [point.lon, point.lat]),
|
||||||
|
profile: graphHopperProfile,
|
||||||
|
elevation: true,
|
||||||
|
points_encoded: false,
|
||||||
|
details: graphhopperDetails,
|
||||||
|
custom_model: privateRoads
|
||||||
|
? {}
|
||||||
|
: graphhopperBlockPrivateCustomModels[graphHopperProfile] || {},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const error = await response.json();
|
||||||
|
if (error.message.includes('Cannot find point 0')) {
|
||||||
|
throw new Error('toolbar.routing.error.from');
|
||||||
|
} else if (error.message.includes('Cannot find point 1')) {
|
||||||
|
if (points.length == 3) {
|
||||||
|
throw new Error('toolbar.routing.error.via');
|
||||||
|
} else {
|
||||||
|
throw new Error('toolbar.routing.error.to');
|
||||||
|
}
|
||||||
|
} else if (error.hints[0].details.includes('PointDistanceExceededException')) {
|
||||||
|
throw new Error('toolbar.routing.error.distance');
|
||||||
|
} else if (error.hints[0].details.includes('ConnectionNotFoundException')) {
|
||||||
|
throw new Error('toolbar.routing.error.connection');
|
||||||
|
} else {
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = await response.json();
|
||||||
|
|
||||||
|
let route: TrackPoint[] = [];
|
||||||
|
let coordinates = json.paths[0].points.coordinates;
|
||||||
|
let details = json.paths[0].details;
|
||||||
|
|
||||||
|
for (let i = 0; i < coordinates.length; i++) {
|
||||||
|
route.push(
|
||||||
|
new TrackPoint({
|
||||||
|
attributes: {
|
||||||
|
lat: coordinates[i][1],
|
||||||
|
lon: coordinates[i][0],
|
||||||
|
},
|
||||||
|
ele: coordinates[i][2] ?? (i > 0 ? route[i - 1].ele : 0),
|
||||||
|
extensions: {},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let key of graphhopperDetails) {
|
||||||
|
let detail = details[key];
|
||||||
|
for (let i = 0; i < detail.length; i++) {
|
||||||
|
for (let j = detail[i][0]; j < detail[i][1] + (i == detail.length - 1); j++) {
|
||||||
|
if (detail[i][2] !== undefined && detail[i][2] !== 'missing') {
|
||||||
|
if (key === 'road_class') {
|
||||||
|
route[j].setExtension('highway', detail[i][2]);
|
||||||
|
} else if (key === 'hike_rating') {
|
||||||
|
const sacScale = hikeRatingToSACScale[detail[i][2]];
|
||||||
|
if (sacScale) {
|
||||||
|
route[j].setExtension('sac_scale', sacScale);
|
||||||
|
}
|
||||||
|
} else if (key === 'mtb_rating') {
|
||||||
|
const mtbScale = mtbRatingToScale[detail[i][2]];
|
||||||
|
if (mtbScale) {
|
||||||
|
route[j].setExtension('mtb_scale', mtbScale);
|
||||||
|
}
|
||||||
|
} else if (key === 'surface' && detail[i][2] !== 'other') {
|
||||||
|
route[j].setExtension('surface', detail[i][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBRouterRoute(
|
||||||
|
points: Coordinates[],
|
||||||
|
brouterProfile: string
|
||||||
|
): Promise<TrackPoint[]> {
|
||||||
|
let url = `https://brouter.de/brouter?lonlats=${points.map((point) => `${point.lon.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile}&format=geojson&alternativeidx=0`;
|
||||||
|
|
||||||
let response = await fetch(url);
|
let response = await fetch(url);
|
||||||
|
|
||||||
// Check if the response is ok
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`${await response.text()}`);
|
const error = await response.text();
|
||||||
|
if (error.includes('from-position not mapped in existing datafile')) {
|
||||||
|
throw new Error('toolbar.routing.error.from');
|
||||||
|
} else if (error.includes('via1-position not mapped in existing datafile')) {
|
||||||
|
throw new Error('toolbar.routing.error.via');
|
||||||
|
} else if (error.includes('to-position not mapped in existing datafile')) {
|
||||||
|
throw new Error('toolbar.routing.error.to');
|
||||||
|
} else if (error.includes('Time-out')) {
|
||||||
|
throw new Error('toolbar.routing.error.timeout');
|
||||||
|
} else {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let geojson = await response.json();
|
let geojson = await response.json();
|
||||||
@@ -52,14 +228,13 @@ async function getRoute(
|
|||||||
let tags = messageIdx < messages.length ? getTags(messages[messageIdx][tagIdx]) : {};
|
let tags = messageIdx < messages.length ? getTags(messages[messageIdx][tagIdx]) : {};
|
||||||
|
|
||||||
for (let i = 0; i < coordinates.length; i++) {
|
for (let i = 0; i < coordinates.length; i++) {
|
||||||
let coord = coordinates[i];
|
|
||||||
route.push(
|
route.push(
|
||||||
new TrackPoint({
|
new TrackPoint({
|
||||||
attributes: {
|
attributes: {
|
||||||
lat: coord[1],
|
lat: coordinates[i][1],
|
||||||
lon: coord[0],
|
lon: coordinates[i][0],
|
||||||
},
|
},
|
||||||
ele: coord[2] ?? (i > 0 ? route[i - 1].ele : 0),
|
ele: coordinates[i][2] ?? (i > 0 ? route[i - 1].ele : 0),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ type DistanceUnits = 'metric' | 'imperial' | 'nautical';
|
|||||||
type VelocityUnits = 'speed' | 'pace';
|
type VelocityUnits = 'speed' | 'pace';
|
||||||
type TemperatureUnits = 'celsius' | 'fahrenheit';
|
type TemperatureUnits = 'celsius' | 'fahrenheit';
|
||||||
type AdditionalDataset = 'speed' | 'hr' | 'cad' | 'atemp' | 'power';
|
type AdditionalDataset = 'speed' | 'hr' | 'cad' | 'atemp' | 'power';
|
||||||
type ElevationFill = 'slope' | 'surface' | undefined;
|
type ElevationFill = 'slope' | 'surface' | 'highway' | undefined;
|
||||||
type RoutingProfile =
|
type RoutingProfile =
|
||||||
| 'bike'
|
| 'bike'
|
||||||
| 'racing_bike'
|
| 'racing_bike'
|
||||||
@@ -223,7 +223,7 @@ export const settings = {
|
|||||||
elevationFill: new Setting<ElevationFill>(
|
elevationFill: new Setting<ElevationFill>(
|
||||||
'elevationFill',
|
'elevationFill',
|
||||||
undefined,
|
undefined,
|
||||||
getValueValidator(['slope', 'surface', undefined], undefined)
|
getValueValidator(['slope', 'surface', 'highway', undefined], undefined)
|
||||||
),
|
),
|
||||||
treeFileView: new Setting<boolean>('fileView', false),
|
treeFileView: new Setting<boolean>('fileView', false),
|
||||||
minimizeRoutingMenu: new Setting('minimizeRoutingMenu', false),
|
minimizeRoutingMenu: new Setting('minimizeRoutingMenu', false),
|
||||||
@@ -254,7 +254,7 @@ export const settings = {
|
|||||||
previousBasemap: new Setting(
|
previousBasemap: new Setting(
|
||||||
'previousBasemap',
|
'previousBasemap',
|
||||||
defaultBasemap,
|
defaultBasemap,
|
||||||
getLayerValidator(Object.keys(basemaps), defaultBasemap)
|
getLayerValidator(basemaps, defaultBasemap)
|
||||||
),
|
),
|
||||||
selectedBasemapTree: new Setting(
|
selectedBasemapTree: new Setting(
|
||||||
'selectedBasemapTree',
|
'selectedBasemapTree',
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"ctrl": "Ctrl",
|
"ctrl": "Ctrl",
|
||||||
"click": "Click",
|
"click": "Click",
|
||||||
"drag": "Drag",
|
"drag": "Drag",
|
||||||
|
"right_click_drag": "Right-click drag",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"button": "Info...",
|
"button": "Info...",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@@ -190,6 +191,8 @@
|
|||||||
"from": "The start point is too far from the nearest road",
|
"from": "The start point is too far from the nearest road",
|
||||||
"via": "The via point is too far from the nearest road",
|
"via": "The via point is too far from the nearest road",
|
||||||
"to": "The end point is too far from the nearest road",
|
"to": "The end point is too far from the nearest road",
|
||||||
|
"distance": "The end point is too far from the start point",
|
||||||
|
"connection": "No connection found between the points",
|
||||||
"timeout": "Route calculation took too long, try adding points closer together"
|
"timeout": "Route calculation took too long, try adding points closer together"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -300,6 +303,7 @@
|
|||||||
"switzerland": "Switzerland",
|
"switzerland": "Switzerland",
|
||||||
"united_kingdom": "United Kingdom",
|
"united_kingdom": "United Kingdom",
|
||||||
"united_states": "United States",
|
"united_states": "United States",
|
||||||
|
"maptilerStreets": "MapTiler Streets",
|
||||||
"maptilerTopo": "MapTiler Topo",
|
"maptilerTopo": "MapTiler Topo",
|
||||||
"maptilerOutdoors": "MapTiler Outdoors",
|
"maptilerOutdoors": "MapTiler Outdoors",
|
||||||
"maptilerSatellite": "MapTiler Satellite",
|
"maptilerSatellite": "MapTiler Satellite",
|
||||||
@@ -489,7 +493,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"contribute": "Contribute",
|
"contribute": "Contribute",
|
||||||
"supported_by": "supported by",
|
"supported_by": "supported by",
|
||||||
"support_button": "Support gpx.studio on Ko-fi",
|
"support_button": "Support gpx.studio on Open Collective",
|
||||||
"route_planning": "Route planning",
|
"route_planning": "Route planning",
|
||||||
"route_planning_description": "An intuitive interface to create itineraries tailored to each sport, based on OpenStreetMap data.",
|
"route_planning_description": "An intuitive interface to create itineraries tailored to each sport, based on OpenStreetMap data.",
|
||||||
"file_processing": "Advanced file processing",
|
"file_processing": "Advanced file processing",
|
||||||
|
|||||||
@@ -282,7 +282,7 @@
|
|||||||
"update": "更新图层"
|
"update": "更新图层"
|
||||||
},
|
},
|
||||||
"opacity": "图层透明度",
|
"opacity": "图层透明度",
|
||||||
"terrain": "Terrain source",
|
"terrain": "地形来源",
|
||||||
"label": {
|
"label": {
|
||||||
"basemaps": "底图",
|
"basemaps": "底图",
|
||||||
"overlays": "叠加层",
|
"overlays": "叠加层",
|
||||||
@@ -326,7 +326,7 @@
|
|||||||
"usgs": "USGS",
|
"usgs": "USGS",
|
||||||
"bikerouterGravel": "bikerouter.de Gravel",
|
"bikerouterGravel": "bikerouter.de Gravel",
|
||||||
"cyclOSMlite": "CyclOSM Lite",
|
"cyclOSMlite": "CyclOSM Lite",
|
||||||
"mapterhornHillshade": "Mapterhorn Hillshade",
|
"mapterhornHillshade": "山体阴影",
|
||||||
"openRailwayMap": "OpenRailwayMap",
|
"openRailwayMap": "OpenRailwayMap",
|
||||||
"swisstopoSlope": "Swisstopo Slope",
|
"swisstopoSlope": "Swisstopo Slope",
|
||||||
"swisstopoHiking": "Swisstopo Hiking",
|
"swisstopoHiking": "Swisstopo Hiking",
|
||||||
|
|||||||
@@ -254,7 +254,7 @@
|
|||||||
{#await data.fundingModule then fundingModule}
|
{#await data.fundingModule then fundingModule}
|
||||||
<DocsContainer module={fundingModule.default} />
|
<DocsContainer module={fundingModule.default} />
|
||||||
{/await}
|
{/await}
|
||||||
<Button href="https://ko-fi.com/gpxstudio" target="_blank" class="text-base">
|
<Button href="https://opencollective.com/gpxstudio" target="_blank" class="text-base">
|
||||||
<Heart size="16" fill="var(--support)" color="var(--support)" />
|
<Heart size="16" fill="var(--support)" color="var(--support)" />
|
||||||
<span>{i18n._('homepage.support_button')}</span>
|
<span>{i18n._('homepage.support_button')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
bind:offsetWidth={bottomPanelWidth}
|
bind:offsetWidth={bottomPanelWidth}
|
||||||
class="flex {bottomPanelOrientation == 'vertical'
|
class="flex {bottomPanelOrientation == 'vertical'
|
||||||
? 'flex-col'
|
? 'flex-col'
|
||||||
: 'flex-row py-2'} gap-1 px-2"
|
: 'flex-row py-2'} gap-1 px-4"
|
||||||
style={$elevationProfile ? `height: ${$bottomPanelSize}px` : ''}
|
style={$elevationProfile ? `height: ${$bottomPanelSize}px` : ''}
|
||||||
>
|
>
|
||||||
<GPXStatistics
|
<GPXStatistics
|
||||||
|
|||||||
Reference in New Issue
Block a user