mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-09-11 18:19:57 +00:00
Compare commits
27
Commits
fa732b0343
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a0d434371 | ||
|
|
b319440a57 | ||
|
|
b0d78b5f3c | ||
|
|
fde6bafc10 | ||
|
|
4537ea4730 | ||
|
|
1954bbd764 | ||
|
|
9d2da80893 | ||
|
|
043d368c74 | ||
|
|
bb11d3375b | ||
|
|
bfe5961e27 | ||
|
|
17559913fd | ||
|
|
55590d68a6 | ||
|
|
8e9f16c460 | ||
|
|
c60b64f24f | ||
|
|
fdb6fe4e52 | ||
|
|
0bf168e67e | ||
|
|
d762a45eb9 | ||
|
|
548ab9a459 | ||
|
|
315c1f6a61 | ||
|
|
98257bee12 | ||
|
|
5561b7d9fe | ||
|
|
320887206c | ||
|
|
04a1bf6a55 | ||
|
|
0989371874 | ||
|
|
3dcd6e52d3 | ||
|
|
0f06d0d461 | ||
|
|
db33310a10 |
Generated
+70
-67
@@ -20,7 +20,7 @@
|
||||
"immer": "^10.1.1",
|
||||
"jszip": "^3.10.1",
|
||||
"mapillary-js": "^4.1.2",
|
||||
"maplibre-gl": "^5.21.1",
|
||||
"maplibre-gl": "^6.0.0",
|
||||
"sanitize-html": "^2.17.0",
|
||||
"sortablejs": "^1.15.6"
|
||||
},
|
||||
@@ -3236,13 +3236,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz",
|
||||
"integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
"node": ">= 22"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/point-geometry": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz",
|
||||
"integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@mapbox/sphericalmercator": {
|
||||
@@ -3253,24 +3258,32 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@mapbox/tiny-sdf": {
|
||||
"version": "2.0.7",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz",
|
||||
"integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@mapbox/unitbezier": {
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
|
||||
"integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@mapbox/vector-tile": {
|
||||
"version": "2.0.4",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-3.0.0.tgz",
|
||||
"integrity": "sha512-Qf10S1uIHMk20ri/IVBnpS+esUEkVaR5Hftmz88jTInrpmWgPGJfPe3LVjjlE77trLx8tH6qjTG7uWH9hIq/0Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "~1.1.0",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
"pbf": "^4.0.1"
|
||||
"pbf": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/vector-tile/node_modules/pbf": {
|
||||
"version": "4.0.1",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
|
||||
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
@@ -3279,18 +3292,13 @@
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/whoots-js": {
|
||||
"version": "3.1.0",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/geojson-vt": {
|
||||
"version": "6.0.4",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz",
|
||||
"integrity": "sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"kdbush": "^4.0.2"
|
||||
"kdbush": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-geocoder": {
|
||||
@@ -3311,15 +3319,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||
"version": "24.8.1",
|
||||
"version": "26.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.2.1.tgz",
|
||||
"integrity": "sha512-QFKCXkOeSzOr8jF75jm6kySOg+dUvOehPhRi68gcOYPHb7U5JloUq0dJW0Y5/fZV8ygfT0Vp2RWodvq+fyxFWA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||
"@mapbox/unitbezier": "^0.0.1",
|
||||
"@mapbox/jsonlint-lines-primitives": "^2.0.3",
|
||||
"@mapbox/unitbezier": "^1.0.0",
|
||||
"json-stringify-pretty-compact": "^4.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"quickselect": "^3.0.0",
|
||||
"rw": "^1.3.3",
|
||||
"tinyqueue": "^3.0.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -3329,31 +3338,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/mlt": {
|
||||
"version": "1.1.8",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.12.tgz",
|
||||
"integrity": "sha512-ZeK5w2TTeHOajcLaEQs1KZXw2V9wIKo1PmThlxlsHoXsQsYlBqLJzPOd6tJHRtGTChUY3DPPmjXRArYVvAbmZw==",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/vt-pbf": {
|
||||
"version": "4.3.0",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.2.tgz",
|
||||
"integrity": "sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "^1.1.0",
|
||||
"@mapbox/vector-tile": "^2.0.4",
|
||||
"@maplibre/geojson-vt": "^5.0.4",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
"@types/supercluster": "^7.1.3",
|
||||
"pbf": "^4.0.1",
|
||||
"supercluster": "^8.0.1"
|
||||
"pbf": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/vt-pbf/node_modules/@maplibre/geojson-vt": {
|
||||
"version": "5.0.4",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@maplibre/vt-pbf/node_modules/pbf": {
|
||||
"version": "4.0.1",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
|
||||
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
@@ -4289,13 +4296,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/supercluster": {
|
||||
"version": "7.1.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.134.0",
|
||||
"license": "MIT"
|
||||
@@ -5720,6 +5720,8 @@
|
||||
},
|
||||
"node_modules/json-stringify-pretty-compact": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
|
||||
"integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jszip": {
|
||||
@@ -5733,7 +5735,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/kdbush": {
|
||||
"version": "4.0.2",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz",
|
||||
"integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
@@ -6154,25 +6158,25 @@
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/maplibre-gl": {
|
||||
"version": "5.22.0",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.0.0.tgz",
|
||||
"integrity": "sha512-1wBgEhzTZfA+cDpFdt0fM1mJA5mJ90fifORJ7D8JcKLJCvPT/iTx9bNxkP7DqEYde65DJd7gE7h83khwNRqdyg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
|
||||
"@mapbox/point-geometry": "^1.1.0",
|
||||
"@mapbox/tiny-sdf": "^2.0.7",
|
||||
"@mapbox/unitbezier": "^0.0.1",
|
||||
"@mapbox/vector-tile": "^2.0.4",
|
||||
"@mapbox/whoots-js": "^3.1.0",
|
||||
"@maplibre/geojson-vt": "^6.0.4",
|
||||
"@maplibre/maplibre-gl-style-spec": "^24.8.1",
|
||||
"@maplibre/mlt": "^1.1.8",
|
||||
"@maplibre/vt-pbf": "^4.3.0",
|
||||
"@mapbox/tiny-sdf": "^2.2.0",
|
||||
"@mapbox/unitbezier": "^1.0.0",
|
||||
"@mapbox/vector-tile": "^3.0.0",
|
||||
"@maplibre/geojson-vt": "^6.1.1",
|
||||
"@maplibre/maplibre-gl-style-spec": "^26.1.0",
|
||||
"@maplibre/mlt": "^1.1.12",
|
||||
"@maplibre/vt-pbf": "^4.3.2",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
"earcut": "^3.0.2",
|
||||
"earcut": "^3.2.3",
|
||||
"gl-matrix": "^3.4.4",
|
||||
"kdbush": "^4.0.2",
|
||||
"kdbush": "^4.1.0",
|
||||
"murmurhash-js": "^1.0.0",
|
||||
"pbf": "^4.0.1",
|
||||
"pbf": "^5.1.2",
|
||||
"potpack": "^2.1.0",
|
||||
"quickselect": "^3.0.0",
|
||||
"tinyqueue": "^3.0.0"
|
||||
@@ -6186,11 +6190,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/maplibre-gl/node_modules/earcut": {
|
||||
"version": "3.0.2",
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.2.3.tgz",
|
||||
"integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/maplibre-gl/node_modules/pbf": {
|
||||
"version": "4.0.1",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
|
||||
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
@@ -6251,6 +6259,8 @@
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -6785,6 +6795,8 @@
|
||||
},
|
||||
"node_modules/quickselect": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
||||
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/rbush": {
|
||||
@@ -6920,10 +6932,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/rw": {
|
||||
"version": "1.3.3",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"license": "Apache-2.0",
|
||||
@@ -7157,13 +7165,6 @@
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supercluster": {
|
||||
"version": "8.0.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"kdbush": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -7405,6 +7406,8 @@
|
||||
},
|
||||
"node_modules/tinyqueue": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
|
||||
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/totalist": {
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"immer": "^10.1.1",
|
||||
"jszip": "^3.10.1",
|
||||
"mapillary-js": "^4.1.2",
|
||||
"maplibre-gl": "^5.21.1",
|
||||
"maplibre-gl": "^6.0.0",
|
||||
"sanitize-html": "^2.17.0",
|
||||
"sortablejs": "^1.15.6"
|
||||
}
|
||||
|
||||
@@ -1168,7 +1168,7 @@ export type CustomLayer = {
|
||||
maxZoom: number;
|
||||
layerType: 'basemap' | 'overlay';
|
||||
resourceType: 'raster' | 'vector';
|
||||
value: string | maplibregl.StyleSpecification;
|
||||
value: string | StyleSpecification;
|
||||
};
|
||||
|
||||
type OverpassQueryData = {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import CustomControl from './custom-control';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import type { Map } from 'maplibre-gl';
|
||||
|
||||
let {
|
||||
position = 'top-right',
|
||||
@@ -17,7 +18,7 @@
|
||||
let control: CustomControl | null = null;
|
||||
|
||||
onMount(() => {
|
||||
map.onLoad((map: maplibregl.Map) => {
|
||||
map.onLoad((map: Map) => {
|
||||
if (position.includes('right')) container.classList.add('float-right');
|
||||
else container.classList.add('float-left');
|
||||
container.classList.remove('hidden');
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { MapPopup } from '$lib/components/map/map-popup';
|
||||
import type { Map } from 'maplibre-gl';
|
||||
|
||||
export let waypointPopup: MapPopup | null = null;
|
||||
export let trackpointPopup: MapPopup | null = null;
|
||||
|
||||
export function createPopups(map: maplibregl.Map) {
|
||||
export function createPopups(map: Map) {
|
||||
removePopups();
|
||||
waypointPopup = new MapPopup(map, {
|
||||
closeButton: false,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { get, type Readable } from 'svelte/store';
|
||||
import maplibregl, {
|
||||
import {
|
||||
type GeoJSONSource,
|
||||
type FilterSpecification,
|
||||
type MapLayerMouseEvent,
|
||||
type MapLayerTouchEvent,
|
||||
Point,
|
||||
} from 'maplibre-gl';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import { waypointPopup, trackpointPopup } from './gpx-layer-popup';
|
||||
@@ -120,7 +121,7 @@ export class GPXLayer {
|
||||
selected: boolean = false;
|
||||
currentWaypointData: GeoJSON.FeatureCollection | null = null;
|
||||
draggedWaypointIndex: number | null = null;
|
||||
draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0);
|
||||
draggingStartingPosition: Point = new Point(0, 0);
|
||||
unsubscribe: Function[] = [];
|
||||
|
||||
updateBinded: () => void = this.update.bind(this);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { Layers } from '@lucide/svelte';
|
||||
import { settings } from '$lib/logic/settings';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import type { Map } from 'maplibre-gl';
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let overpassLayer: OverpassLayer;
|
||||
@@ -21,7 +22,7 @@
|
||||
selectedOverpassTree,
|
||||
} = settings;
|
||||
|
||||
map.onLoad((_map: maplibregl.Map) => {
|
||||
map.onLoad((_map: Map) => {
|
||||
if (overpassLayer) {
|
||||
overpassLayer.remove();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
poi: PopupItem<any>;
|
||||
} = $props();
|
||||
|
||||
let tags: Record<string, string> = $derived(poi ? JSON.parse(poi.item.tags) : {});
|
||||
let tags: Record<string, string> = $derived(
|
||||
poi ? (typeof poi.item.tags == 'object' ? poi.item.tags : JSON.parse(poi.item.tags)) : {}
|
||||
);
|
||||
let name = $derived.by(() => {
|
||||
if (poi) {
|
||||
if (tags.name !== undefined && tags.name !== '') {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { overpassQueryData } from '$lib/assets/layers';
|
||||
import { MapPopup } from '$lib/components/map/map-popup';
|
||||
import { settings } from '$lib/logic/settings';
|
||||
import { db } from '$lib/db';
|
||||
import type { GeoJSONSource } from 'maplibre-gl';
|
||||
import type { Map as MapLibreMap, GeoJSONSource } from 'maplibre-gl';
|
||||
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
||||
import { loadSVGIcon } from '$lib/utils';
|
||||
@@ -28,7 +28,7 @@ export class OverpassLayer {
|
||||
minZoom = 12;
|
||||
queryZoom = 12;
|
||||
expirationTime = 7 * 24 * 3600 * 1000;
|
||||
map: maplibregl.Map;
|
||||
map: MapLibreMap;
|
||||
layerEventManager: MapLayerEventManager;
|
||||
popup: MapPopup;
|
||||
|
||||
@@ -40,7 +40,7 @@ export class OverpassLayer {
|
||||
updateBinded = this.update.bind(this);
|
||||
onHoverBinded = this.onHover.bind(this);
|
||||
|
||||
constructor(map: maplibregl.Map, layerEventManager: MapLayerEventManager) {
|
||||
constructor(map: MapLibreMap, layerEventManager: MapLayerEventManager) {
|
||||
this.map = map;
|
||||
this.layerEventManager = layerEventManager;
|
||||
this.popup = new MapPopup(map, {
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { fileStateCollection } from '$lib/logic/file-state';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import {
|
||||
LngLatBounds,
|
||||
MapMouseEvent,
|
||||
MapTouchEvent,
|
||||
Point,
|
||||
type Map,
|
||||
type MapGeoJSONFeature,
|
||||
type MapLayerMouseEvent,
|
||||
type MapLayerTouchEvent,
|
||||
} from 'maplibre-gl';
|
||||
|
||||
type MapLayerMouseEventListener = (e: maplibregl.MapLayerMouseEvent) => void;
|
||||
type MapLayerTouchEventListener = (e: maplibregl.MapLayerTouchEvent) => void;
|
||||
type MapLayerMouseEventListener = (e: MapLayerMouseEvent) => void;
|
||||
type MapLayerTouchEventListener = (e: MapLayerTouchEvent) => void;
|
||||
type MapLayerListener = {
|
||||
features: maplibregl.MapGeoJSONFeature[];
|
||||
features: MapGeoJSONFeature[];
|
||||
mousemoves: MapLayerMouseEventListener[];
|
||||
mouseenters: MapLayerMouseEventListener[];
|
||||
mouseleaves: MapLayerMouseEventListener[];
|
||||
@@ -15,10 +24,10 @@ type MapLayerListener = {
|
||||
};
|
||||
|
||||
export class MapLayerEventManager {
|
||||
private _map: maplibregl.Map;
|
||||
private _map: Map;
|
||||
private _listeners: Record<string, MapLayerListener> = {};
|
||||
|
||||
constructor(map: maplibregl.Map) {
|
||||
constructor(map: Map) {
|
||||
this._map = map;
|
||||
this._map.on('mousemove', this._handleMouseMove.bind(this));
|
||||
this._map.on('click', this._handleMouseClick.bind(this, 'click'));
|
||||
@@ -141,7 +150,7 @@ export class MapLayerEventManager {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
|
||||
private _handleMouseMove(e: MapMouseEvent) {
|
||||
if (e.originalEvent.buttons > 0) return;
|
||||
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||
Object.keys(this._listeners).forEach((layerId) => {
|
||||
@@ -150,29 +159,20 @@ export class MapLayerEventManager {
|
||||
if ((features.length == 0) != (listener.features.length == 0)) {
|
||||
if (features.length > 0) {
|
||||
if (listener.mouseenters.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent(
|
||||
'mouseenter',
|
||||
e.target,
|
||||
e.originalEvent,
|
||||
{
|
||||
features: featuresByLayer[layerId]!,
|
||||
}
|
||||
);
|
||||
const event = new MapMouseEvent('mouseenter', e.target, e.originalEvent, {
|
||||
features: featuresByLayer[layerId]!,
|
||||
});
|
||||
listener.mouseenters.forEach((l) => l(event));
|
||||
}
|
||||
} else {
|
||||
if (listener.mouseleaves.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent(
|
||||
'mouseleave',
|
||||
e.target,
|
||||
e.originalEvent
|
||||
);
|
||||
const event = new MapMouseEvent('mouseleave', e.target, e.originalEvent);
|
||||
listener.mouseleaves.forEach((l) => l(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (features.length > 0 && listener.mousemoves.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent('mousemove', e.target, e.originalEvent, {
|
||||
const event = new MapMouseEvent('mousemove', e.target, e.originalEvent, {
|
||||
features: featuresByLayer[layerId]!,
|
||||
});
|
||||
listener.mousemoves.forEach((l) => l(event));
|
||||
@@ -181,49 +181,39 @@ export class MapLayerEventManager {
|
||||
});
|
||||
}
|
||||
|
||||
private _handleMouseClick(type: string, e: maplibregl.MapMouseEvent) {
|
||||
private _handleMouseClick(type: string, e: MapMouseEvent) {
|
||||
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||
Object.keys(this._listeners).forEach((layerId) => {
|
||||
const features = featuresByLayer[layerId] || [];
|
||||
const listener = this._listeners[layerId];
|
||||
if (features.length > 0) {
|
||||
if (type === 'click' && listener.clicks.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent('click', e.target, e.originalEvent, {
|
||||
const event = new MapMouseEvent('click', e.target, e.originalEvent, {
|
||||
features: features,
|
||||
});
|
||||
listener.clicks.forEach((l) => l(event));
|
||||
} else if (type === 'contextmenu' && listener.contextmenus.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent(
|
||||
'contextmenu',
|
||||
e.target,
|
||||
e.originalEvent,
|
||||
{
|
||||
features: features,
|
||||
}
|
||||
);
|
||||
const event = new MapMouseEvent('contextmenu', e.target, e.originalEvent, {
|
||||
features: features,
|
||||
});
|
||||
listener.contextmenus.forEach((l) => l(event));
|
||||
} else if (type === 'mousedown' && listener.mousedowns.length > 0) {
|
||||
const event = new maplibregl.MapMouseEvent(
|
||||
'mousedown',
|
||||
e.target,
|
||||
e.originalEvent,
|
||||
{
|
||||
features: features,
|
||||
}
|
||||
);
|
||||
const event = new MapMouseEvent('mousedown', e.target, e.originalEvent, {
|
||||
features: features,
|
||||
});
|
||||
listener.mousedowns.forEach((l) => l(event));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _handleTouchStart(e: maplibregl.MapTouchEvent) {
|
||||
private _handleTouchStart(e: MapTouchEvent) {
|
||||
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
|
||||
Object.keys(this._listeners).forEach((layerId) => {
|
||||
const features = featuresByLayer[layerId] || [];
|
||||
const listener = this._listeners[layerId];
|
||||
if (features.length > 0) {
|
||||
const event: maplibregl.MapLayerTouchEvent = new maplibregl.MapTouchEvent(
|
||||
const event: MapLayerTouchEvent = new MapTouchEvent(
|
||||
'touchstart',
|
||||
e.target,
|
||||
e.originalEvent
|
||||
@@ -234,18 +224,15 @@ export class MapLayerEventManager {
|
||||
});
|
||||
}
|
||||
|
||||
private _getBounds(point: maplibregl.Point) {
|
||||
private _getBounds(point: Point) {
|
||||
const delta = 30;
|
||||
return new maplibregl.LngLatBounds(
|
||||
return new LngLatBounds(
|
||||
this._map.unproject([point.x - delta, point.y + delta]),
|
||||
this._map.unproject([point.x + delta, point.y - delta])
|
||||
);
|
||||
}
|
||||
|
||||
private _filterLayersIntersectingBounds(
|
||||
layerIds: string[],
|
||||
bounds: maplibregl.LngLatBounds
|
||||
): string[] {
|
||||
private _filterLayersIntersectingBounds(layerIds: string[], bounds: LngLatBounds): string[] {
|
||||
let result = layerIds.filter((layerId) => {
|
||||
if (!this._map.getLayer(layerId)) return false;
|
||||
const fileId = layerId.replace('-waypoints', '');
|
||||
@@ -261,7 +248,7 @@ export class MapLayerEventManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
private _getRenderedFeaturesByLayer(e: maplibregl.MapMouseEvent | maplibregl.MapTouchEvent) {
|
||||
private _getRenderedFeaturesByLayer(e: MapMouseEvent | MapTouchEvent) {
|
||||
const layerIds = this._filterLayersIntersectingBounds(
|
||||
Object.keys(this._listeners),
|
||||
this._getBounds(e.point)
|
||||
@@ -270,7 +257,7 @@ export class MapLayerEventManager {
|
||||
layerIds.length > 0
|
||||
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
|
||||
: [];
|
||||
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
|
||||
const featuresByLayer: Record<string, MapGeoJSONFeature[]> = {};
|
||||
features.forEach((f) => {
|
||||
if (!featuresByLayer[f.layer.id]) {
|
||||
featuresByLayer[f.layer.id] = [];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TrackPoint, Waypoint } from 'gpx';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { LngLat, Map, MapMouseEvent, Popup, type PopupOptions } from 'maplibre-gl';
|
||||
import { mount, tick, unmount } from 'svelte';
|
||||
import { get, writable, type Writable } from 'svelte/store';
|
||||
import MapPopupComponent from '$lib/components/map/MapPopup.svelte';
|
||||
@@ -11,15 +11,15 @@ export type PopupItem<T = Waypoint | TrackPoint | any> = {
|
||||
};
|
||||
|
||||
export class MapPopup {
|
||||
map: maplibregl.Map;
|
||||
popup: maplibregl.Popup;
|
||||
map: Map;
|
||||
popup: Popup;
|
||||
item: Writable<PopupItem | null> = writable(null);
|
||||
component: ReturnType<typeof mount>;
|
||||
maybeHideBinded = this.maybeHide.bind(this);
|
||||
|
||||
constructor(map: maplibregl.Map, options?: maplibregl.PopupOptions) {
|
||||
constructor(map: Map, options?: PopupOptions) {
|
||||
this.map = map;
|
||||
this.popup = new maplibregl.Popup(options);
|
||||
this.popup = new Popup(options);
|
||||
this.component = mount(MapPopupComponent, {
|
||||
target: document.body,
|
||||
props: {
|
||||
@@ -51,7 +51,7 @@ export class MapPopup {
|
||||
this.map.on('mousemove', this.maybeHideBinded);
|
||||
}
|
||||
|
||||
maybeHide(e: maplibregl.MapMouseEvent) {
|
||||
maybeHide(e: MapMouseEvent) {
|
||||
const item = get(this.item);
|
||||
if (item === null) {
|
||||
this.hide();
|
||||
@@ -75,10 +75,10 @@ export class MapPopup {
|
||||
getCoordinates() {
|
||||
const item = get(this.item);
|
||||
if (item === null) {
|
||||
return new maplibregl.LngLat(0, 0);
|
||||
return new LngLat(0, 0);
|
||||
}
|
||||
return item.item instanceof Waypoint || item.item instanceof TrackPoint
|
||||
? item.item.getCoordinates()
|
||||
: new maplibregl.LngLat(item.item.lon, item.item.lat);
|
||||
: new LngLat(item.item.lon, item.item.lat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import * as maplibregl from 'maplibre-gl';
|
||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
|
||||
import MaplibreGeocoder, {
|
||||
type MaplibreGeocoderFeatureResults,
|
||||
} from '@maplibre/maplibre-gl-geocoder';
|
||||
@@ -39,6 +40,7 @@ export class MapLibreGLMap {
|
||||
geocoder: boolean,
|
||||
geolocate: boolean
|
||||
) {
|
||||
maplibregl.setWorkerUrl(workerUrl);
|
||||
this._maptilerKey = maptilerKey;
|
||||
this._styleManager = new StyleManager(this._mapStore, this._maptilerKey);
|
||||
const map = new maplibregl.Map({
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { i18n } from '$lib/i18n.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte';
|
||||
import type { Map } from 'maplibre-gl';
|
||||
|
||||
const { streetViewSource } = settings;
|
||||
|
||||
@@ -20,7 +21,7 @@
|
||||
let container: HTMLElement;
|
||||
|
||||
onMount(() => {
|
||||
map.onLoad((map_: maplibregl.Map) => {
|
||||
map.onLoad((map_: Map) => {
|
||||
googleRedirect = new GoogleRedirect(map_);
|
||||
mapillaryLayer = new MapillaryLayer(
|
||||
map_,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
import type { Map, MapMouseEvent } from 'maplibre-gl';
|
||||
|
||||
export class GoogleRedirect {
|
||||
map: maplibregl.Map;
|
||||
map: Map;
|
||||
enabled = false;
|
||||
|
||||
constructor(map: maplibregl.Map) {
|
||||
constructor(map: Map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@@ -24,7 +25,7 @@ export class GoogleRedirect {
|
||||
this.map.off('click', this.openStreetView);
|
||||
}
|
||||
|
||||
openStreetView(e: maplibregl.MapMouseEvent) {
|
||||
openStreetView(e: MapMouseEvent) {
|
||||
window.open(
|
||||
`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${e.lngLat.lat},${e.lngLat.lng}`
|
||||
);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import maplibregl, { type LayerSpecification, type VectorSourceSpecification } from 'maplibre-gl';
|
||||
import {
|
||||
Map,
|
||||
Marker,
|
||||
type LayerSpecification,
|
||||
type MapLayerMouseEvent,
|
||||
type VectorSourceSpecification,
|
||||
} from 'maplibre-gl';
|
||||
import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
|
||||
import 'mapillary-js/dist/mapillary.css';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
@@ -43,9 +49,9 @@ const mapillaryImageLayer: LayerSpecification = {
|
||||
};
|
||||
|
||||
export class MapillaryLayer {
|
||||
map: maplibregl.Map;
|
||||
map: Map;
|
||||
layerEventManager: MapLayerEventManager;
|
||||
marker: maplibregl.Marker;
|
||||
marker: Marker;
|
||||
viewer: Viewer;
|
||||
|
||||
active = false;
|
||||
@@ -56,7 +62,7 @@ export class MapillaryLayer {
|
||||
onMouseLeaveBinded = this.onMouseLeave.bind(this);
|
||||
|
||||
constructor(
|
||||
map: maplibregl.Map,
|
||||
map: Map,
|
||||
layerEventManager: MapLayerEventManager,
|
||||
container: HTMLElement,
|
||||
popupOpen: { value: boolean }
|
||||
@@ -75,7 +81,7 @@ export class MapillaryLayer {
|
||||
dot.className = 'maplibregl-user-location-dot';
|
||||
element.appendChild(dot);
|
||||
|
||||
this.marker = new maplibregl.Marker({
|
||||
this.marker = new Marker({
|
||||
rotationAlignment: 'map',
|
||||
element,
|
||||
});
|
||||
@@ -140,7 +146,7 @@ export class MapillaryLayer {
|
||||
this.popupOpen.value = false;
|
||||
}
|
||||
|
||||
onMouseEnter(e: maplibregl.MapLayerMouseEvent) {
|
||||
onMouseEnter(e: MapLayerMouseEvent) {
|
||||
if (
|
||||
e.features &&
|
||||
e.features.length > 0 &&
|
||||
|
||||
@@ -9,11 +9,17 @@ import {
|
||||
} from '$lib/assets/layers';
|
||||
import { getLayers } from '$lib/components/map/layer-control/utils';
|
||||
import { i18n } from '$lib/i18n.svelte';
|
||||
import type {
|
||||
Map,
|
||||
GeoJSONSourceSpecification,
|
||||
LayerSpecification,
|
||||
StyleSpecification,
|
||||
} from 'maplibre-gl';
|
||||
|
||||
const { currentBasemap, currentOverlays, customLayers, opacities, terrainSource, distanceUnits } =
|
||||
settings;
|
||||
|
||||
const emptySource: maplibregl.GeoJSONSourceSpecification = {
|
||||
const emptySource: GeoJSONSourceSpecification = {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'FeatureCollection',
|
||||
@@ -32,18 +38,18 @@ export const ANCHOR_LAYER_KEY = {
|
||||
waypoints: 'waypoints-end',
|
||||
routingControls: 'routing-controls-end',
|
||||
};
|
||||
const anchorLayers: maplibregl.LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
|
||||
const anchorLayers: LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
|
||||
id: id,
|
||||
type: 'symbol',
|
||||
source: 'empty-source',
|
||||
}));
|
||||
|
||||
export class StyleManager {
|
||||
private _map: Writable<maplibregl.Map | null>;
|
||||
private _map: Writable<Map | null>;
|
||||
private _maptilerKey: string;
|
||||
private _pastOverlays: Set<string> = new Set();
|
||||
|
||||
constructor(map: Writable<maplibregl.Map | null>, maptilerKey: string) {
|
||||
constructor(map: Writable<Map | null>, maptilerKey: string) {
|
||||
this._map = map;
|
||||
this._maptilerKey = maptilerKey;
|
||||
this._map.subscribe((map_) => {
|
||||
@@ -76,10 +82,10 @@ export class StyleManager {
|
||||
});
|
||||
}
|
||||
|
||||
async buildStyle(basemap: string): Promise<maplibregl.StyleSpecification> {
|
||||
async buildStyle(basemap: string): Promise<StyleSpecification> {
|
||||
const custom = get(customLayers);
|
||||
|
||||
const style: maplibregl.StyleSpecification = {
|
||||
const style: StyleSpecification = {
|
||||
version: 8,
|
||||
projection: {
|
||||
type: 'globe',
|
||||
@@ -92,7 +98,7 @@ export class StyleManager {
|
||||
|
||||
const basemapInfo = basemaps[basemap] ?? custom[basemap]?.value ?? basemaps[defaultBasemap];
|
||||
|
||||
let basemapStyle = basemaps.openStreetMap as maplibregl.StyleSpecification;
|
||||
let basemapStyle = basemaps.openStreetMap as StyleSpecification;
|
||||
try {
|
||||
basemapStyle = await this.get(basemapInfo);
|
||||
for (const source in basemapStyle.sources) {
|
||||
@@ -203,9 +209,7 @@ export class StyleManager {
|
||||
}
|
||||
}
|
||||
|
||||
async get(
|
||||
styleInfo: maplibregl.StyleSpecification | string
|
||||
): Promise<maplibregl.StyleSpecification> {
|
||||
async get(styleInfo: StyleSpecification | string): Promise<StyleSpecification> {
|
||||
if (typeof styleInfo === 'string') {
|
||||
let styleUrl = styleInfo as string;
|
||||
const response = await fetch(styleUrl, { cache: 'force-cache' });
|
||||
@@ -219,7 +223,7 @@ export class StyleManager {
|
||||
}
|
||||
}
|
||||
|
||||
merge(style: maplibregl.StyleSpecification, other: maplibregl.StyleSpecification) {
|
||||
merge(style: StyleSpecification, other: StyleSpecification) {
|
||||
style.sources = { ...style.sources, ...other.sources };
|
||||
const units = get(distanceUnits);
|
||||
for (let layer of other.layers ?? []) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import Clean from '$lib/components/toolbar/tools/Clean.svelte';
|
||||
import Reduce from '$lib/components/toolbar/tools/reduce/Reduce.svelte';
|
||||
import RoutingControlPopup from '$lib/components/toolbar/tools/routing/RoutingControlPopup.svelte';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { Popup } from 'maplibre-gl';
|
||||
import { settings } from '$lib/logic/settings';
|
||||
|
||||
let {
|
||||
@@ -23,11 +23,11 @@
|
||||
const { minimizeRoutingMenu } = settings;
|
||||
|
||||
let popupElement: HTMLDivElement | undefined = $state(undefined);
|
||||
let popup: maplibregl.Popup | undefined = $derived.by(() => {
|
||||
let popup: Popup | undefined = $derived.by(() => {
|
||||
if (!popupElement) {
|
||||
return undefined;
|
||||
}
|
||||
let popup = new maplibregl.Popup({
|
||||
let popup = new Popup({
|
||||
closeButton: false,
|
||||
maxWidth: undefined,
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import { getURLForLanguage } from '$lib/utils';
|
||||
import { Trash2 } from '@lucide/svelte';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import type { GeoJSONSource } from 'maplibre-gl';
|
||||
import type { GeoJSONSource, LngLat } from 'maplibre-gl';
|
||||
import { selection } from '$lib/logic/selection';
|
||||
import { fileActions } from '$lib/logic/file-actions';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
@@ -29,7 +29,7 @@
|
||||
let cleanType = $state(CleanType.INSIDE);
|
||||
let deleteTrackpoints = $state(true);
|
||||
let deleteWaypoints = $state(true);
|
||||
let rectangleCoordinates: maplibregl.LngLat[] = $state([]);
|
||||
let rectangleCoordinates: LngLat[] = $state([]);
|
||||
|
||||
$effect(() => {
|
||||
if ($map) {
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
import { fileActions, getFileIds, newGPXFile } from '$lib/logic/file-actions';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
import { RoutingControls, routingControls } from './routing-controls';
|
||||
import type { Popup } from 'maplibre-gl';
|
||||
|
||||
let {
|
||||
minimized = $bindable(false),
|
||||
@@ -51,7 +52,7 @@
|
||||
}: {
|
||||
minimized?: boolean;
|
||||
minimizable?: boolean;
|
||||
popup?: maplibregl.Popup;
|
||||
popup?: Popup;
|
||||
popupElement?: HTMLDivElement;
|
||||
class?: string;
|
||||
} = $props();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedPoint } from 'gpx';
|
||||
import { get, writable, type Readable } from 'svelte/store';
|
||||
import maplibregl, {
|
||||
import {
|
||||
type MapMouseEvent,
|
||||
type GeoJSONSource,
|
||||
type MapLayerMouseEvent,
|
||||
type MapLayerTouchEvent,
|
||||
Popup,
|
||||
Point,
|
||||
} from 'maplibre-gl';
|
||||
import { route } from './routing';
|
||||
import { toast } from 'svelte-sonner';
|
||||
@@ -50,7 +52,7 @@ export class RoutingControls {
|
||||
}
|
||||
> = new Map();
|
||||
anchors: GeoJSON.Feature<GeoJSON.Point, AnchorProperties>[] = [];
|
||||
popup: maplibregl.Popup;
|
||||
popup: Popup;
|
||||
popupElement: HTMLElement;
|
||||
fileUnsubscribe: () => void = () => {};
|
||||
unsubscribes: Function[] = [];
|
||||
@@ -61,7 +63,7 @@ export class RoutingControls {
|
||||
|
||||
draggedAnchorIndex: number | null = null;
|
||||
lastDraggedAnchorEventTime: number = 0;
|
||||
draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0);
|
||||
draggingStartingPosition: Point = new Point(0, 0);
|
||||
onMouseEnterBinded: () => void = this.onMouseEnter.bind(this);
|
||||
onMouseLeaveBinded: () => void = this.onMouseLeave.bind(this);
|
||||
onClickBinded: (e: MapLayerMouseEvent) => void = this.onClick.bind(this);
|
||||
@@ -80,7 +82,7 @@ export class RoutingControls {
|
||||
constructor(
|
||||
fileId: string,
|
||||
file: Readable<GPXFileWithStatistics | undefined>,
|
||||
popup: maplibregl.Popup,
|
||||
popup: Popup,
|
||||
popupElement: HTMLElement
|
||||
) {
|
||||
this.fileId = fileId;
|
||||
@@ -183,7 +185,7 @@ export class RoutingControls {
|
||||
|
||||
this.layers.forEach((layer, zoom) => {
|
||||
try {
|
||||
let source = map_.getSource(layer.id) as maplibregl.GeoJSONSource | undefined;
|
||||
let source = map_.getSource(layer.id) as GeoJSONSource | undefined;
|
||||
if (source) {
|
||||
source.setData({
|
||||
type: 'FeatureCollection',
|
||||
@@ -520,7 +522,7 @@ export class RoutingControls {
|
||||
});
|
||||
}
|
||||
|
||||
async appendAnchor(e: maplibregl.MapMouseEvent) {
|
||||
async appendAnchor(e: MapMouseEvent) {
|
||||
// Add a new anchor to the end of the last segment
|
||||
if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
|
||||
return;
|
||||
@@ -609,7 +611,7 @@ export class RoutingControls {
|
||||
await this.routeBetweenAnchors([lastAnchor, newAnchor], [lastAnchorPoint, newAnchorPoint]);
|
||||
}
|
||||
|
||||
addIntermediateAnchor(e: maplibregl.MapMouseEvent) {
|
||||
addIntermediateAnchor(e: MapMouseEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
if (this.temporaryAnchor !== null) {
|
||||
|
||||
@@ -8,13 +8,13 @@ import { get } from 'svelte/store';
|
||||
import { fileStateCollection } from '$lib/logic/file-state';
|
||||
import { fileActions } from '$lib/logic/file-actions';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
import type { GeoJSONSource } from 'maplibre-gl';
|
||||
import type { Map, GeoJSONSource, MapLayerMouseEvent } from 'maplibre-gl';
|
||||
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
|
||||
import type { MapLayerEventManager } from '$lib/components/map/map-layer-event-manager';
|
||||
import { loadSVGIcon } from '$lib/utils';
|
||||
|
||||
export class SplitControls {
|
||||
map: maplibregl.Map;
|
||||
map: Map;
|
||||
layerEventManager: MapLayerEventManager;
|
||||
unsubscribes: Function[] = [];
|
||||
|
||||
@@ -22,7 +22,7 @@ export class SplitControls {
|
||||
layerOnMouseLeaveBinded: () => void = this.layerOnMouseLeave.bind(this);
|
||||
layerOnClickBinded: (e: any) => void = this.layerOnClick.bind(this);
|
||||
|
||||
constructor(map: maplibregl.Map, layerEventManager: MapLayerEventManager) {
|
||||
constructor(map: Map, layerEventManager: MapLayerEventManager) {
|
||||
this.map = map;
|
||||
this.layerEventManager = layerEventManager;
|
||||
loadSVGIcon(
|
||||
@@ -160,7 +160,7 @@ export class SplitControls {
|
||||
mapCursor.notify(MapCursorState.SPLIT_CONTROL, false);
|
||||
}
|
||||
|
||||
layerOnClick(e: maplibregl.MapLayerMouseEvent) {
|
||||
layerOnClick(e: MapLayerMouseEvent) {
|
||||
let coordinates = (e.features![0].geometry as GeoJSON.Point).coordinates;
|
||||
fileActions.split(
|
||||
get(splitAs),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import { fileActions } from '$lib/logic/file-actions';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { Marker } from 'maplibre-gl';
|
||||
import { getSvgForSymbol } from '$lib/components/map/gpx-layer/gpx-layer';
|
||||
|
||||
let props: {
|
||||
@@ -41,7 +41,7 @@
|
||||
})
|
||||
);
|
||||
|
||||
let marker: maplibregl.Marker | null = null;
|
||||
let marker: Marker | null = null;
|
||||
|
||||
function reset() {
|
||||
if ($selectedWaypoint) {
|
||||
@@ -125,7 +125,7 @@
|
||||
let element = document.createElement('div');
|
||||
element.classList.add('w-8', 'h-8');
|
||||
element.innerHTML = getSvgForSymbol(symbolKey);
|
||||
marker = new maplibregl.Marker({
|
||||
marker = new Marker({
|
||||
element,
|
||||
anchor: 'bottom',
|
||||
})
|
||||
|
||||
@@ -19,6 +19,6 @@ Mit diesem Tool kannst du Höhendaten zu Routen und [Points of Interest] (../gpx
|
||||
<DocsNote>
|
||||
|
||||
Elevation data is provided by <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>.
|
||||
Mehr über die Herkunft und Genauigkeit erfährst du in der <a href="https://mapterhorn.com/attribution/" target="_blank">Dokumentation</a>.
|
||||
You can learn more about its origin and accuracy in the <a href="https://mapterhorn.com/attribution/" target="_blank">documentation</a>.
|
||||
|
||||
</DocsNote>
|
||||
|
||||
@@ -13,8 +13,8 @@ title: Integrazioa
|
||||
|
||||
Behar duzun guztia hau da:
|
||||
|
||||
1. Zure zerbitzarian edo Google Drive-n ostatatutako GPX fitxategiak, edo URL publiko baten bidez eskura daitezke;
|
||||
2. _Aukerakoa:_ <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">MapTiler tekla</a> MapTiler mapak kargatzeko.
|
||||
1. GPX files hosted on your server or on Google Drive, or accessible via a public URL;
|
||||
2. _Optional:_ a <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">MapTiler key</a> to load MapTiler maps.
|
||||
|
||||
Ondoren, konfiguratzailearekin jolastu dezakezu zure mapa pertsonalizatzeko eta dagokion HTML kodea sortzeko.
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ Maparen geruzen botoiak mapa-oinarri desberdinen artean aldatzeko aukera ematen
|
||||
<DocsLayers />
|
||||
<span class="text-sm text-center mt-2">
|
||||
|
||||
Pasa ezazu maparen gainean <a href="https://hiking.waymarkedtrails.org" target="_blank">markatutako mendi-ibiliak</a> gainjartzeko oinarrizko mapa topografikoaren gainean.
|
||||
Hover over the map to show the <a href="https://hiking.waymarkedtrails.org" target="_blank">Waymarked Trails hiking</a> overlay on top of the topographic basemap.
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -69,4 +69,4 @@ Global eta tokiko mapa oinarri bilduma handia dago **gpx.studio**-n eskuragarri,
|
||||
|
||||
Ezarpen horietan, gainjartzeen opakutasuna ere kudeatu dezakezu.
|
||||
|
||||
Erabiltzaile aurreratuentzat, oinarrizko mapa pertsonalizatuak eta gainjartzeak gehi daitezke <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a> edo <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a>https:///malibrea-spec.org/malibrea-spec. target="_blank">MapLibre estiloko JSON</a> URLak.
|
||||
For advanced users, it is possible to add custom basemaps and overlays by providing <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a>, or <a href="https://maplibre.org/maplibre-style-spec/" target="_blank">MapLibre style JSON</a> URLs.
|
||||
|
||||
@@ -48,6 +48,7 @@ Maparen orientazioa eta okertzea kontrolatzeko, mapa ere arrasta dezakezu <kbd>
|
||||
|
||||
</DocsNote>
|
||||
|
||||
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Pantaila osoa
|
||||
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Full screen
|
||||
|
||||
Sartu edo irten pantaila osoko moduan.<kbd>F11</kbd> ere saka dezakezu txandakatzeko, edo <kbd>Ihes</kbd> irteteko.
|
||||
Enter or exit full screen mode.
|
||||
You can also press <kbd>F11</kbd> to toggle, or <kbd>Escape</kbd> to exit.
|
||||
|
||||
@@ -18,7 +18,7 @@ Tresna honen bidez elebazio datuak gehitzen ahal dira ibilbidetan eta [interesgu
|
||||
|
||||
<DocsNote>
|
||||
|
||||
Altueraren datuak <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>k ematen ditu.
|
||||
Haren jatorriari eta zehaztasunari buruz gehiago jakin dezakezu <a href="https://mapterhorn.com/attribution/" target="_blank">dokumentazioan</a>.
|
||||
Elevation data is provided by <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>.
|
||||
You can learn more about its origin and accuracy in the <a href="https://mapterhorn.com/attribution/" target="_blank">documentation</a>.
|
||||
|
||||
</DocsNote>
|
||||
|
||||
@@ -18,8 +18,8 @@ Tresna hau erabiltzeko [hautatu](../files-and-stats) behar duzu hainbat fitxateg
|
||||
|
||||
<DocsNote>
|
||||
|
||||
Hautatutako elementuak fitxategien zerrendan agertzen diren ordenan batzen dira.
|
||||
Berrantolatu elementuak arrastatu eta jareginez, behar izanez gero.
|
||||
Selected items are merged in the order they appear in the files list.
|
||||
Reorder items by drag-and-drop if needed.
|
||||
|
||||
</DocsNote>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ title: Stijging
|
||||
|
||||
# <MountainSnow size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||
|
||||
Met deze tool kunt u hoogtegegevens toevoegen aan sporen en [punten van belang](../gpx) of de bestaande gegevens vervangen.
|
||||
Met dit gereedschap kun je hoogtegegevens toevoegen aan sporen en [interessante punten](../gpx), of de bestaande gegevens vervangen.
|
||||
|
||||
<div class="flex flex-row justify-center">
|
||||
<Elevation class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||
|
||||
@@ -71,7 +71,7 @@ title: Планирование и редактирование маршрута
|
||||
|
||||
Изменить направление маршрута на противоположное.
|
||||
|
||||
### <House size="16" class="inline-block" style="margin-bottom: 2px" /> Вернуться в начало
|
||||
### <House size="16" class="inline-block" style="margin-bottom: 2px" /> Back to start
|
||||
|
||||
Подсоедините последнюю точку маршрута к начальной точке, используя выбранные параметры маршрутизации.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ title: 檔案和統計
|
||||
|
||||
Once you have [opened](./menu/file) files, they will be shown as tabs in the file list located at the bottom of the map.
|
||||
You can reorder them by dragging and dropping the tabs.
|
||||
當開啟的檔案較多時,也可以捲動分頁清單,在不同檔案之間切換。
|
||||
And when many files are open, you can scroll through the list of tabs to navigate between them.
|
||||
|
||||
<DocsNote>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ title: 設定
|
||||
|
||||
### <Ruler size="16" class="inline-block" style="margin-bottom: 2px" /> 距離單位
|
||||
|
||||
變更介面中顯示距離時所使用的單位。
|
||||
Change the units used to display distances in the interface.
|
||||
|
||||
### <Zap size="16" class="inline-block" style="margin-bottom: 2px" /> Velocity units
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 檢視選項
|
||||
title: View options
|
||||
---
|
||||
|
||||
<script lang="ts">
|
||||
@@ -9,38 +9,38 @@ title: 檢視選項
|
||||
|
||||
# { title }
|
||||
|
||||
此選單提供重新排列介面與地圖檢視方式的選項。
|
||||
This menu provides options to rearrange the interface and the map view.
|
||||
|
||||
### <ChartArea size="16" class="inline-block" style="margin-bottom: 2px" /> 高度剖面圖
|
||||
### <ChartArea size="16" class="inline-block" style="margin-bottom: 2px" /> Elevation profile
|
||||
|
||||
隱藏高度剖面圖以騰出更多地圖空間,或顯示高度剖面圖以查看目前的選取內容。
|
||||
Hide the elevation profile to make room for the map, or show it to inspect the current selection.
|
||||
|
||||
### <ListTree size="16" class="inline-block" style="margin-bottom: 2px" /> 檔案樹狀結構
|
||||
### <ListTree size="16" class="inline-block" style="margin-bottom: 2px" /> File tree
|
||||
|
||||
切換[檔案清單](../files-and-stats)的樹狀版面配置。
|
||||
Toggle the tree layout for the [file list](../files-and-stats).
|
||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||
此外,檔案樹狀檢視可讓你透過可收合的區段,查看檔案中包含的[軌跡、區段和興趣點](../gpx)。
|
||||
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
|
||||
|
||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> 切換至上一個底圖
|
||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
||||
|
||||
將底圖變更為先前透過[地圖圖層控制項](../map-controls)選取的底圖。
|
||||
Change the basemap to the one previously selected through the [map layer control](../map-controls).
|
||||
|
||||
### <Layers2 size="16" class="inline-block" style="margin-bottom: 2px" /> 切換疊加圖層
|
||||
### <Layers2 size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle overlays
|
||||
|
||||
切換透過[地圖圖層控制項](../map-controls)選取之地圖疊加圖層的顯示狀態。
|
||||
Toggle the visibility of the map overlays selected through the [map layer control](../map-controls).
|
||||
|
||||
### <Coins size="16" class="inline-block" style="margin-bottom: 2px" /> 距離標記
|
||||
### <Coins size="16" class="inline-block" style="margin-bottom: 2px" /> Distance markers
|
||||
|
||||
切換地圖上距離標記的顯示狀態。
|
||||
距離標記會針對目前的選取內容顯示,就像[高度剖面圖](../files-and-stats)一樣。
|
||||
Toggle the visibility of distance markers on the map.
|
||||
They are displayed for the current selection, like the [elevation profile](../files-and-stats).
|
||||
|
||||
### <Milestone size="16" class="inline-block" style="margin-bottom: 2px" /> 方向箭頭
|
||||
### <Milestone size="16" class="inline-block" style="margin-bottom: 2px" /> Direction arrows
|
||||
|
||||
切換地圖上方向箭頭的顯示狀態。
|
||||
Toggle the visibility of direction arrows on the map.
|
||||
|
||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> 切換 3D
|
||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
||||
|
||||
進入或離開 3D 地圖檢視。
|
||||
Enter or exit the 3D map view.
|
||||
|
||||
<DocsNote>
|
||||
|
||||
@@ -48,7 +48,7 @@ To control the orientation and tilt of the map, you can also drag the map while
|
||||
|
||||
</DocsNote>
|
||||
|
||||
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> 全螢幕
|
||||
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Full screen
|
||||
|
||||
進入或離開全螢幕模式。
|
||||
你也可以按下 <kbd>F11</kbd> 來切換,或按下 <kbd>Escape</kbd> 離開。
|
||||
Enter or exit full screen mode.
|
||||
You can also press <kbd>F11</kbd> to toggle, or <kbd>Escape</kbd> to exit.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { get } from 'svelte/store';
|
||||
import { selection } from '$lib/logic/selection';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { LngLatBounds } from 'maplibre-gl';
|
||||
import { ListFileItem, ListWaypointItem } from '$lib/components/file-list/file-list';
|
||||
import { fileStateCollection, GPXFileStateCollectionObserver } from '$lib/logic/file-state';
|
||||
import { gpxStatistics } from '$lib/logic/statistics';
|
||||
@@ -10,7 +10,7 @@ import type { Coordinates } from 'gpx';
|
||||
import { page } from '$app/state';
|
||||
|
||||
export class BoundsManager {
|
||||
private _bounds: maplibregl.LngLatBounds = new maplibregl.LngLatBounds();
|
||||
private _bounds: LngLatBounds = new LngLatBounds();
|
||||
private _files: Set<string> = new Set();
|
||||
private _fileStateCollectionObserver: GPXFileStateCollectionObserver | null = null;
|
||||
private _unsubscribes: (() => void)[] = [];
|
||||
@@ -87,12 +87,12 @@ export class BoundsManager {
|
||||
}
|
||||
this._unsubscribes.forEach((unsubscribe) => unsubscribe());
|
||||
this._unsubscribes = [];
|
||||
this._bounds = new maplibregl.LngLatBounds([180, 90, -180, -90]);
|
||||
this._bounds = new LngLatBounds([180, 90, -180, -90]);
|
||||
}
|
||||
|
||||
centerMapOnSelection() {
|
||||
let selected = get(selection).getSelected();
|
||||
let bounds = new maplibregl.LngLatBounds();
|
||||
let bounds = new LngLatBounds();
|
||||
|
||||
if (selected.find((item) => item instanceof ListWaypointItem)) {
|
||||
selection.applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { ListItem, ListLevel } from '$lib/components/file-list/file-list';
|
||||
import { GPXFile, GPXStatistics, GPXStatisticsGroup, type Track } from 'gpx';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { LngLatBounds } from 'maplibre-gl';
|
||||
|
||||
export class GPXStatisticsTree {
|
||||
level: ListLevel;
|
||||
statistics: {
|
||||
[key: string]: GPXStatisticsTree | GPXStatistics;
|
||||
} = {};
|
||||
wptBounds: maplibregl.LngLatBounds;
|
||||
wptBounds: LngLatBounds;
|
||||
|
||||
constructor(element: GPXFile | Track) {
|
||||
this.wptBounds = new maplibregl.LngLatBounds();
|
||||
this.wptBounds = new LngLatBounds();
|
||||
if (element instanceof GPXFile) {
|
||||
this.level = ListLevel.FILE;
|
||||
element.children.forEach((child, index) => {
|
||||
@@ -49,11 +49,11 @@ export class GPXStatisticsTree {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
intersectsBBox(bounds: maplibregl.LngLatBounds): boolean {
|
||||
intersectsBBox(bounds: LngLatBounds): boolean {
|
||||
for (let key in this.statistics) {
|
||||
const stats = this.statistics[key];
|
||||
if (stats instanceof GPXStatistics) {
|
||||
const bbox = new maplibregl.LngLatBounds(
|
||||
const bbox = new LngLatBounds(
|
||||
stats.global.bounds.southWest,
|
||||
stats.global.bounds.northEast
|
||||
);
|
||||
@@ -67,7 +67,7 @@ export class GPXStatisticsTree {
|
||||
return false;
|
||||
}
|
||||
|
||||
intersectsWaypointBBox(bounds: maplibregl.LngLatBounds): boolean {
|
||||
intersectsWaypointBBox(bounds: LngLatBounds): boolean {
|
||||
return !this.wptBounds.isEmpty() && this.wptBounds.intersects(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { twMerge } from 'tailwind-merge';
|
||||
import { base } from '$app/paths';
|
||||
import { languages } from '$lib/languages';
|
||||
import { TrackPoint, Waypoint, type Coordinates, crossarcDistance, distance, GPXFile } from 'gpx';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { Map as MapLibreMap, LngLatBounds } from 'maplibre-gl';
|
||||
import { pointToTile, pointToTileFraction } from '@mapbox/tilebelt';
|
||||
import type { GPXStatisticsTree } from '$lib/logic/statistics-tree';
|
||||
import { ListTrackSegmentItem } from '$lib/components/file-list/file-list';
|
||||
@@ -58,7 +58,7 @@ export function getClosestTrackSegments(
|
||||
let segmentBounds = segmentStatistics.global.bounds;
|
||||
let northEast = segmentBounds.northEast;
|
||||
let southWest = segmentBounds.southWest;
|
||||
let bounds = new maplibregl.LngLatBounds(southWest, northEast);
|
||||
let bounds = new LngLatBounds(southWest, northEast);
|
||||
if (bounds.contains(point)) {
|
||||
segmentBoundsDistances.push([0, trackIndex, segmentIndex]);
|
||||
} else {
|
||||
@@ -106,7 +106,7 @@ export function getElevation(
|
||||
let coordinates = points.map((point) =>
|
||||
point instanceof TrackPoint || point instanceof Waypoint ? point.getCoordinates() : point
|
||||
);
|
||||
let bbox = new maplibregl.LngLatBounds();
|
||||
let bbox = new LngLatBounds();
|
||||
coordinates.forEach((coord) => bbox.extend(coord));
|
||||
|
||||
let tiles = coordinates.map((coord) => pointToTile(coord.lon, coord.lat, ELEVATION_ZOOM));
|
||||
@@ -193,7 +193,7 @@ export function getElevation(
|
||||
);
|
||||
}
|
||||
|
||||
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string, size: number = 100) {
|
||||
export function loadSVGIcon(map: MapLibreMap, id: string, svg: string, size: number = 100) {
|
||||
if (!map.hasImage(id)) {
|
||||
let icon = new Image(size, size);
|
||||
icon.onload = () => {
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
"path": "Sendero",
|
||||
"pedestrian": "Peatonal",
|
||||
"cycleway": "Ciclovía",
|
||||
"steps": "Pasos",
|
||||
"steps": "Escalones",
|
||||
"road": "Carretera",
|
||||
"bridleway": "Ruta ecuestre",
|
||||
"platform": "Plataforma",
|
||||
@@ -230,7 +230,7 @@
|
||||
"extract": {
|
||||
"tooltip": "Extraer contenidos en elementos separados",
|
||||
"button": "Extraer",
|
||||
"help": "La extracción del contenido de los elementos seleccionados creará un elemento separado para cada uno de sus contenidos.",
|
||||
"help": "Al extraer los contenidos de los elementos seleccionados creará un elemento separado para cada uno.",
|
||||
"help_invalid_selection": "Su selección debe contener elementos con múltiples trazas para extraerlos."
|
||||
},
|
||||
"elevation": {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"export": "Exporteren...",
|
||||
"export_all": "Alles exporteren...",
|
||||
"export_options": "Exporteer instellingen",
|
||||
"support_message": "De tool is gratis te gebruiken, maar is niet gratis om te onderhouden. Overweeg om de website te ondersteunen als je hem vaak gebruikt. Bedankt!",
|
||||
"support_message": "Het gereedschap is gratis te gebruiken, maar is niet gratis om te onderhouden. Overweeg om de website te ondersteunen als je hem vaak gebruikt. Bedankt!",
|
||||
"support_button": "Help de website gratis te houden",
|
||||
"download_file": "Bestand downloaden",
|
||||
"download_files": "Bestanden downloaden",
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"ctrl": "Ctrl",
|
||||
"click": "Clique",
|
||||
"drag": "Arrastar",
|
||||
"right_click_drag": "Clique direito arraste",
|
||||
"right_click_drag": "Right-click drag",
|
||||
"metadata": {
|
||||
"button": "Informações...",
|
||||
"name": "Nome",
|
||||
@@ -181,7 +181,7 @@
|
||||
},
|
||||
"sac_scale": {
|
||||
"hiking": "Caminhada",
|
||||
"mountain_hiking": "",
|
||||
"mountain_hiking": "Mountain hiking",
|
||||
"demanding_mountain_hiking": "Demanding mountain hiking",
|
||||
"alpine_hiking": "Alpine hiking",
|
||||
"demanding_alpine_hiking": "Demanding alpine hiking",
|
||||
@@ -239,7 +239,7 @@
|
||||
"help_no_selection": "Select a file item to request elevation data."
|
||||
},
|
||||
"waypoint": {
|
||||
"tooltip": "Criar ponto de interesse",
|
||||
"tooltip": "Create and edit points of interest",
|
||||
"icon": "Icon",
|
||||
"link": "Link",
|
||||
"longitude": "Longitude",
|
||||
|
||||
Reference in New Issue
Block a user