15 Commits
Author SHA1 Message Date
vcoppe fa732b0343 New translations en.json (Portuguese)
[ci skip]
2026-09-02 03:11:59 +02:00
vcoppe 142ee61484 New translations en.json (Portuguese)
[ci skip]
2026-09-02 02:14:31 +02:00
vcoppe 873059cfcc New translations view.mdx (Chinese Traditional, Hong Kong)
[ci skip]
2026-08-14 12:27:32 +02:00
vcoppe 9e380e597e New translations settings.mdx (Chinese Traditional, Hong Kong)
[ci skip]
2026-08-14 12:27:30 +02:00
vcoppe f4dc516fe5 New translations files-and-stats.mdx (Chinese Traditional, Hong Kong)
[ci skip]
2026-08-14 10:41:57 +02:00
vcoppe bca6c32193 New translations routing.mdx (Russian)
[ci skip]
2026-08-11 14:53:35 +02:00
vcoppe 9f52d4d60d New translations elevation.mdx (Dutch)
[ci skip]
2026-08-10 14:56:55 +02:00
vcoppe a1475ab7ba New translations en.json (Dutch)
[ci skip]
2026-08-10 14:56:54 +02:00
vcoppe 0987c6a72e New translations elevation.mdx (Basque)
[ci skip]
2026-08-06 17:52:04 +02:00
vcoppe a02de61d0a New translations merge.mdx (Basque)
[ci skip]
2026-08-06 17:52:03 +02:00
vcoppe 75e477ba52 New translations view.mdx (Basque)
[ci skip]
2026-08-06 17:52:01 +02:00
vcoppe b72cebc186 New translations map-controls.mdx (Basque)
[ci skip]
2026-08-06 17:51:59 +02:00
vcoppe 5dd53cd9eb New translations integration.mdx (Basque)
[ci skip]
2026-08-06 17:51:58 +02:00
vcoppe 2c82444832 New translations elevation.mdx (German)
[ci skip]
2026-08-01 13:11:15 +02:00
vcoppe 93ac92969d New translations en.json (Spanish)
[ci skip]
2026-07-29 17:33:54 +02:00
39 changed files with 233 additions and 247 deletions
+67 -70
View File
@@ -20,7 +20,7 @@
"immer": "^10.1.1",
"jszip": "^3.10.1",
"mapillary-js": "^4.1.2",
"maplibre-gl": "^6.0.0",
"maplibre-gl": "^5.21.1",
"sanitize-html": "^2.17.0",
"sortablejs": "^1.15.6"
},
@@ -3236,18 +3236,13 @@
}
},
"node_modules/@mapbox/jsonlint-lines-primitives": {
"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",
"version": "2.0.2",
"engines": {
"node": ">= 22"
"node": ">= 0.6"
}
},
"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": {
@@ -3258,32 +3253,24 @@
"license": "MIT"
},
"node_modules/@mapbox/tiny-sdf": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz",
"integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==",
"version": "2.0.7",
"license": "BSD-2-Clause"
},
"node_modules/@mapbox/unitbezier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
"integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
"version": "0.0.1",
"license": "BSD-2-Clause"
},
"node_modules/@mapbox/vector-tile": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-3.0.0.tgz",
"integrity": "sha512-Qf10S1uIHMk20ri/IVBnpS+esUEkVaR5Hftmz88jTInrpmWgPGJfPe3LVjjlE77trLx8tH6qjTG7uWH9hIq/0Q==",
"version": "2.0.4",
"license": "BSD-3-Clause",
"dependencies": {
"@mapbox/point-geometry": "~1.1.0",
"@types/geojson": "^7946.0.16",
"pbf": "^5.0.0"
"pbf": "^4.0.1"
}
},
"node_modules/@mapbox/vector-tile/node_modules/pbf": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
"version": "4.0.1",
"license": "BSD-3-Clause",
"dependencies": {
"resolve-protobuf-schema": "^2.1.0"
@@ -3292,13 +3279,18 @@
"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.1.1",
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz",
"integrity": "sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==",
"version": "6.0.4",
"license": "ISC",
"dependencies": {
"kdbush": "^4.1.0"
"kdbush": "^4.0.2"
}
},
"node_modules/@maplibre/maplibre-gl-geocoder": {
@@ -3319,16 +3311,15 @@
}
},
"node_modules/@maplibre/maplibre-gl-style-spec": {
"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==",
"version": "24.8.1",
"license": "ISC",
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.3",
"@mapbox/unitbezier": "^1.0.0",
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
"@mapbox/unitbezier": "^0.0.1",
"json-stringify-pretty-compact": "^4.0.0",
"minimist": "^1.2.8",
"quickselect": "^3.0.0",
"rw": "^1.3.3",
"tinyqueue": "^3.0.0"
},
"bin": {
@@ -3338,29 +3329,31 @@
}
},
"node_modules/@maplibre/mlt": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.12.tgz",
"integrity": "sha512-ZeK5w2TTeHOajcLaEQs1KZXw2V9wIKo1PmThlxlsHoXsQsYlBqLJzPOd6tJHRtGTChUY3DPPmjXRArYVvAbmZw==",
"version": "1.1.8",
"license": "(MIT OR Apache-2.0)",
"dependencies": {
"@mapbox/point-geometry": "^1.1.0"
}
},
"node_modules/@maplibre/vt-pbf": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.2.tgz",
"integrity": "sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==",
"version": "4.3.0",
"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",
"pbf": "^5.1.0"
"@types/supercluster": "^7.1.3",
"pbf": "^4.0.1",
"supercluster": "^8.0.1"
}
},
"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": "5.1.2",
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
"version": "4.0.1",
"license": "BSD-3-Clause",
"dependencies": {
"resolve-protobuf-schema": "^2.1.0"
@@ -4296,6 +4289,13 @@
"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,8 +5720,6 @@
},
"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": {
@@ -5735,9 +5733,7 @@
}
},
"node_modules/kdbush": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz",
"integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
"version": "4.0.2",
"license": "ISC"
},
"node_modules/keyv": {
@@ -6158,25 +6154,25 @@
"license": "(MIT AND Zlib)"
},
"node_modules/maplibre-gl": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.0.0.tgz",
"integrity": "sha512-1wBgEhzTZfA+cDpFdt0fM1mJA5mJ90fifORJ7D8JcKLJCvPT/iTx9bNxkP7DqEYde65DJd7gE7h83khwNRqdyg==",
"version": "5.22.0",
"license": "BSD-3-Clause",
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
"@mapbox/point-geometry": "^1.1.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",
"@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",
"@types/geojson": "^7946.0.16",
"earcut": "^3.2.3",
"earcut": "^3.0.2",
"gl-matrix": "^3.4.4",
"kdbush": "^4.1.0",
"kdbush": "^4.0.2",
"murmurhash-js": "^1.0.0",
"pbf": "^5.1.2",
"pbf": "^4.0.1",
"potpack": "^2.1.0",
"quickselect": "^3.0.0",
"tinyqueue": "^3.0.0"
@@ -6190,15 +6186,11 @@
}
},
"node_modules/maplibre-gl/node_modules/earcut": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.2.3.tgz",
"integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==",
"version": "3.0.2",
"license": "ISC"
},
"node_modules/maplibre-gl/node_modules/pbf": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
"version": "4.0.1",
"license": "BSD-3-Clause",
"dependencies": {
"resolve-protobuf-schema": "^2.1.0"
@@ -6259,8 +6251,6 @@
},
"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"
@@ -6795,8 +6785,6 @@
},
"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": {
@@ -6932,6 +6920,10 @@
}
}
},
"node_modules/rw": {
"version": "1.3.3",
"license": "BSD-3-Clause"
},
"node_modules/rxjs": {
"version": "7.8.2",
"license": "Apache-2.0",
@@ -7165,6 +7157,13 @@
"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",
@@ -7406,8 +7405,6 @@
},
"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": {
+1 -1
View File
@@ -75,7 +75,7 @@
"immer": "^10.1.1",
"jszip": "^3.10.1",
"mapillary-js": "^4.1.2",
"maplibre-gl": "^6.0.0",
"maplibre-gl": "^5.21.1",
"sanitize-html": "^2.17.0",
"sortablejs": "^1.15.6"
}
+1 -1
View File
@@ -1168,7 +1168,7 @@ export type CustomLayer = {
maxZoom: number;
layerType: 'basemap' | 'overlay';
resourceType: 'raster' | 'vector';
value: string | StyleSpecification;
value: string | maplibregl.StyleSpecification;
};
type OverpassQueryData = {
@@ -2,7 +2,6 @@
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',
@@ -18,7 +17,7 @@
let control: CustomControl | null = null;
onMount(() => {
map.onLoad((map: Map) => {
map.onLoad((map: maplibregl.Map) => {
if (position.includes('right')) container.classList.add('float-right');
else container.classList.add('float-left');
container.classList.remove('hidden');
@@ -1,10 +1,9 @@
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: Map) {
export function createPopups(map: maplibregl.Map) {
removePopups();
waypointPopup = new MapPopup(map, {
closeButton: false,
@@ -1,10 +1,9 @@
import { get, type Readable } from 'svelte/store';
import {
import maplibregl, {
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';
@@ -121,7 +120,7 @@ export class GPXLayer {
selected: boolean = false;
currentWaypointData: GeoJSON.FeatureCollection | null = null;
draggedWaypointIndex: number | null = null;
draggingStartingPosition: Point = new Point(0, 0);
draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0);
unsubscribe: Function[] = [];
updateBinded: () => void = this.update.bind(this);
@@ -7,7 +7,6 @@
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;
@@ -22,7 +21,7 @@
selectedOverpassTree,
} = settings;
map.onLoad((_map: Map) => {
map.onLoad((_map: maplibregl.Map) => {
if (overpassLayer) {
overpassLayer.remove();
}
@@ -15,9 +15,7 @@
poi: PopupItem<any>;
} = $props();
let tags: Record<string, string> = $derived(
poi ? (typeof poi.item.tags == 'object' ? poi.item.tags : JSON.parse(poi.item.tags)) : {}
);
let tags: Record<string, string> = $derived(poi ? 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 { Map as MapLibreMap, GeoJSONSource } from 'maplibre-gl';
import type { 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: MapLibreMap;
map: maplibregl.Map;
layerEventManager: MapLayerEventManager;
popup: MapPopup;
@@ -40,7 +40,7 @@ export class OverpassLayer {
updateBinded = this.update.bind(this);
onHoverBinded = this.onHover.bind(this);
constructor(map: MapLibreMap, layerEventManager: MapLayerEventManager) {
constructor(map: maplibregl.Map, layerEventManager: MapLayerEventManager) {
this.map = map;
this.layerEventManager = layerEventManager;
this.popup = new MapPopup(map, {
@@ -1,19 +1,10 @@
import { fileStateCollection } from '$lib/logic/file-state';
import {
LngLatBounds,
MapMouseEvent,
MapTouchEvent,
Point,
type Map,
type MapGeoJSONFeature,
type MapLayerMouseEvent,
type MapLayerTouchEvent,
} from 'maplibre-gl';
import maplibregl from 'maplibre-gl';
type MapLayerMouseEventListener = (e: MapLayerMouseEvent) => void;
type MapLayerTouchEventListener = (e: MapLayerTouchEvent) => void;
type MapLayerMouseEventListener = (e: maplibregl.MapLayerMouseEvent) => void;
type MapLayerTouchEventListener = (e: maplibregl.MapLayerTouchEvent) => void;
type MapLayerListener = {
features: MapGeoJSONFeature[];
features: maplibregl.MapGeoJSONFeature[];
mousemoves: MapLayerMouseEventListener[];
mouseenters: MapLayerMouseEventListener[];
mouseleaves: MapLayerMouseEventListener[];
@@ -24,10 +15,10 @@ type MapLayerListener = {
};
export class MapLayerEventManager {
private _map: Map;
private _map: maplibregl.Map;
private _listeners: Record<string, MapLayerListener> = {};
constructor(map: Map) {
constructor(map: maplibregl.Map) {
this._map = map;
this._map.on('mousemove', this._handleMouseMove.bind(this));
this._map.on('click', this._handleMouseClick.bind(this, 'click'));
@@ -150,7 +141,7 @@ export class MapLayerEventManager {
}
}
private _handleMouseMove(e: MapMouseEvent) {
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
if (e.originalEvent.buttons > 0) return;
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
Object.keys(this._listeners).forEach((layerId) => {
@@ -159,20 +150,29 @@ export class MapLayerEventManager {
if ((features.length == 0) != (listener.features.length == 0)) {
if (features.length > 0) {
if (listener.mouseenters.length > 0) {
const event = new MapMouseEvent('mouseenter', e.target, e.originalEvent, {
const event = new maplibregl.MapMouseEvent(
'mouseenter',
e.target,
e.originalEvent,
{
features: featuresByLayer[layerId]!,
});
}
);
listener.mouseenters.forEach((l) => l(event));
}
} else {
if (listener.mouseleaves.length > 0) {
const event = new MapMouseEvent('mouseleave', e.target, e.originalEvent);
const event = new maplibregl.MapMouseEvent(
'mouseleave',
e.target,
e.originalEvent
);
listener.mouseleaves.forEach((l) => l(event));
}
}
}
if (features.length > 0 && listener.mousemoves.length > 0) {
const event = new MapMouseEvent('mousemove', e.target, e.originalEvent, {
const event = new maplibregl.MapMouseEvent('mousemove', e.target, e.originalEvent, {
features: featuresByLayer[layerId]!,
});
listener.mousemoves.forEach((l) => l(event));
@@ -181,39 +181,49 @@ export class MapLayerEventManager {
});
}
private _handleMouseClick(type: string, e: MapMouseEvent) {
private _handleMouseClick(type: string, e: maplibregl.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 MapMouseEvent('click', e.target, e.originalEvent, {
const event = new maplibregl.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 MapMouseEvent('contextmenu', e.target, e.originalEvent, {
const event = new maplibregl.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 MapMouseEvent('mousedown', e.target, e.originalEvent, {
const event = new maplibregl.MapMouseEvent(
'mousedown',
e.target,
e.originalEvent,
{
features: features,
});
}
);
listener.mousedowns.forEach((l) => l(event));
}
}
});
}
private _handleTouchStart(e: MapTouchEvent) {
private _handleTouchStart(e: maplibregl.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: MapLayerTouchEvent = new MapTouchEvent(
const event: maplibregl.MapLayerTouchEvent = new maplibregl.MapTouchEvent(
'touchstart',
e.target,
e.originalEvent
@@ -224,15 +234,18 @@ export class MapLayerEventManager {
});
}
private _getBounds(point: Point) {
private _getBounds(point: maplibregl.Point) {
const delta = 30;
return new LngLatBounds(
return new maplibregl.LngLatBounds(
this._map.unproject([point.x - delta, point.y + delta]),
this._map.unproject([point.x + delta, point.y - delta])
);
}
private _filterLayersIntersectingBounds(layerIds: string[], bounds: LngLatBounds): string[] {
private _filterLayersIntersectingBounds(
layerIds: string[],
bounds: maplibregl.LngLatBounds
): string[] {
let result = layerIds.filter((layerId) => {
if (!this._map.getLayer(layerId)) return false;
const fileId = layerId.replace('-waypoints', '');
@@ -248,7 +261,7 @@ export class MapLayerEventManager {
return result;
}
private _getRenderedFeaturesByLayer(e: MapMouseEvent | MapTouchEvent) {
private _getRenderedFeaturesByLayer(e: maplibregl.MapMouseEvent | maplibregl.MapTouchEvent) {
const layerIds = this._filterLayersIntersectingBounds(
Object.keys(this._listeners),
this._getBounds(e.point)
@@ -257,7 +270,7 @@ export class MapLayerEventManager {
layerIds.length > 0
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
: [];
const featuresByLayer: Record<string, MapGeoJSONFeature[]> = {};
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
features.forEach((f) => {
if (!featuresByLayer[f.layer.id]) {
featuresByLayer[f.layer.id] = [];
+8 -8
View File
@@ -1,5 +1,5 @@
import { TrackPoint, Waypoint } from 'gpx';
import { LngLat, Map, MapMouseEvent, Popup, type PopupOptions } from 'maplibre-gl';
import maplibregl 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: Map;
popup: Popup;
map: maplibregl.Map;
popup: maplibregl.Popup;
item: Writable<PopupItem | null> = writable(null);
component: ReturnType<typeof mount>;
maybeHideBinded = this.maybeHide.bind(this);
constructor(map: Map, options?: PopupOptions) {
constructor(map: maplibregl.Map, options?: maplibregl.PopupOptions) {
this.map = map;
this.popup = new Popup(options);
this.popup = new maplibregl.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: MapMouseEvent) {
maybeHide(e: maplibregl.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 LngLat(0, 0);
return new maplibregl.LngLat(0, 0);
}
return item.item instanceof Waypoint || item.item instanceof TrackPoint
? item.item.getCoordinates()
: new LngLat(item.item.lon, item.item.lat);
: new maplibregl.LngLat(item.item.lon, item.item.lat);
}
}
+1 -3
View File
@@ -1,6 +1,5 @@
import * as maplibregl from 'maplibre-gl';
import 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';
@@ -40,7 +39,6 @@ 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,7 +9,6 @@
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;
@@ -21,7 +20,7 @@
let container: HTMLElement;
onMount(() => {
map.onLoad((map_: Map) => {
map.onLoad((map_: maplibregl.Map) => {
googleRedirect = new GoogleRedirect(map_);
mapillaryLayer = new MapillaryLayer(
map_,
@@ -1,11 +1,10 @@
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
import type { Map, MapMouseEvent } from 'maplibre-gl';
export class GoogleRedirect {
map: Map;
map: maplibregl.Map;
enabled = false;
constructor(map: Map) {
constructor(map: maplibregl.Map) {
this.map = map;
}
@@ -25,7 +24,7 @@ export class GoogleRedirect {
this.map.off('click', this.openStreetView);
}
openStreetView(e: MapMouseEvent) {
openStreetView(e: maplibregl.MapMouseEvent) {
window.open(
`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${e.lngLat.lat},${e.lngLat.lng}`
);
@@ -1,10 +1,4 @@
import {
Map,
Marker,
type LayerSpecification,
type MapLayerMouseEvent,
type VectorSourceSpecification,
} from 'maplibre-gl';
import maplibregl, { type LayerSpecification, 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';
@@ -49,9 +43,9 @@ const mapillaryImageLayer: LayerSpecification = {
};
export class MapillaryLayer {
map: Map;
map: maplibregl.Map;
layerEventManager: MapLayerEventManager;
marker: Marker;
marker: maplibregl.Marker;
viewer: Viewer;
active = false;
@@ -62,7 +56,7 @@ export class MapillaryLayer {
onMouseLeaveBinded = this.onMouseLeave.bind(this);
constructor(
map: Map,
map: maplibregl.Map,
layerEventManager: MapLayerEventManager,
container: HTMLElement,
popupOpen: { value: boolean }
@@ -81,7 +75,7 @@ export class MapillaryLayer {
dot.className = 'maplibregl-user-location-dot';
element.appendChild(dot);
this.marker = new Marker({
this.marker = new maplibregl.Marker({
rotationAlignment: 'map',
element,
});
@@ -146,7 +140,7 @@ export class MapillaryLayer {
this.popupOpen.value = false;
}
onMouseEnter(e: MapLayerMouseEvent) {
onMouseEnter(e: maplibregl.MapLayerMouseEvent) {
if (
e.features &&
e.features.length > 0 &&
+11 -15
View File
@@ -9,17 +9,11 @@ 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: GeoJSONSourceSpecification = {
const emptySource: maplibregl.GeoJSONSourceSpecification = {
type: 'geojson',
data: {
type: 'FeatureCollection',
@@ -38,18 +32,18 @@ export const ANCHOR_LAYER_KEY = {
waypoints: 'waypoints-end',
routingControls: 'routing-controls-end',
};
const anchorLayers: LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
const anchorLayers: maplibregl.LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
id: id,
type: 'symbol',
source: 'empty-source',
}));
export class StyleManager {
private _map: Writable<Map | null>;
private _map: Writable<maplibregl.Map | null>;
private _maptilerKey: string;
private _pastOverlays: Set<string> = new Set();
constructor(map: Writable<Map | null>, maptilerKey: string) {
constructor(map: Writable<maplibregl.Map | null>, maptilerKey: string) {
this._map = map;
this._maptilerKey = maptilerKey;
this._map.subscribe((map_) => {
@@ -82,10 +76,10 @@ export class StyleManager {
});
}
async buildStyle(basemap: string): Promise<StyleSpecification> {
async buildStyle(basemap: string): Promise<maplibregl.StyleSpecification> {
const custom = get(customLayers);
const style: StyleSpecification = {
const style: maplibregl.StyleSpecification = {
version: 8,
projection: {
type: 'globe',
@@ -98,7 +92,7 @@ export class StyleManager {
const basemapInfo = basemaps[basemap] ?? custom[basemap]?.value ?? basemaps[defaultBasemap];
let basemapStyle = basemaps.openStreetMap as StyleSpecification;
let basemapStyle = basemaps.openStreetMap as maplibregl.StyleSpecification;
try {
basemapStyle = await this.get(basemapInfo);
for (const source in basemapStyle.sources) {
@@ -209,7 +203,9 @@ export class StyleManager {
}
}
async get(styleInfo: StyleSpecification | string): Promise<StyleSpecification> {
async get(
styleInfo: maplibregl.StyleSpecification | string
): Promise<maplibregl.StyleSpecification> {
if (typeof styleInfo === 'string') {
let styleUrl = styleInfo as string;
const response = await fetch(styleUrl, { cache: 'force-cache' });
@@ -223,7 +219,7 @@ export class StyleManager {
}
}
merge(style: StyleSpecification, other: StyleSpecification) {
merge(style: maplibregl.StyleSpecification, other: maplibregl.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 { Popup } from 'maplibre-gl';
import maplibregl 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: Popup | undefined = $derived.by(() => {
let popup: maplibregl.Popup | undefined = $derived.by(() => {
if (!popupElement) {
return undefined;
}
let popup = new Popup({
let popup = new maplibregl.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, LngLat } from 'maplibre-gl';
import type { GeoJSONSource } 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: LngLat[] = $state([]);
let rectangleCoordinates: maplibregl.LngLat[] = $state([]);
$effect(() => {
if ($map) {
@@ -41,7 +41,6 @@
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),
@@ -52,7 +51,7 @@
}: {
minimized?: boolean;
minimizable?: boolean;
popup?: Popup;
popup?: maplibregl.Popup;
popupElement?: HTMLDivElement;
class?: string;
} = $props();
@@ -1,12 +1,10 @@
import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedPoint } from 'gpx';
import { get, writable, type Readable } from 'svelte/store';
import {
import maplibregl, {
type MapMouseEvent,
type GeoJSONSource,
type MapLayerMouseEvent,
type MapLayerTouchEvent,
Popup,
Point,
} from 'maplibre-gl';
import { route } from './routing';
import { toast } from 'svelte-sonner';
@@ -52,7 +50,7 @@ export class RoutingControls {
}
> = new Map();
anchors: GeoJSON.Feature<GeoJSON.Point, AnchorProperties>[] = [];
popup: Popup;
popup: maplibregl.Popup;
popupElement: HTMLElement;
fileUnsubscribe: () => void = () => {};
unsubscribes: Function[] = [];
@@ -63,7 +61,7 @@ export class RoutingControls {
draggedAnchorIndex: number | null = null;
lastDraggedAnchorEventTime: number = 0;
draggingStartingPosition: Point = new Point(0, 0);
draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0);
onMouseEnterBinded: () => void = this.onMouseEnter.bind(this);
onMouseLeaveBinded: () => void = this.onMouseLeave.bind(this);
onClickBinded: (e: MapLayerMouseEvent) => void = this.onClick.bind(this);
@@ -82,7 +80,7 @@ export class RoutingControls {
constructor(
fileId: string,
file: Readable<GPXFileWithStatistics | undefined>,
popup: Popup,
popup: maplibregl.Popup,
popupElement: HTMLElement
) {
this.fileId = fileId;
@@ -185,7 +183,7 @@ export class RoutingControls {
this.layers.forEach((layer, zoom) => {
try {
let source = map_.getSource(layer.id) as GeoJSONSource | undefined;
let source = map_.getSource(layer.id) as maplibregl.GeoJSONSource | undefined;
if (source) {
source.setData({
type: 'FeatureCollection',
@@ -522,7 +520,7 @@ export class RoutingControls {
});
}
async appendAnchor(e: MapMouseEvent) {
async appendAnchor(e: maplibregl.MapMouseEvent) {
// Add a new anchor to the end of the last segment
if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
return;
@@ -611,7 +609,7 @@ export class RoutingControls {
await this.routeBetweenAnchors([lastAnchor, newAnchor], [lastAnchorPoint, newAnchorPoint]);
}
addIntermediateAnchor(e: MapMouseEvent) {
addIntermediateAnchor(e: maplibregl.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 { Map, GeoJSONSource, MapLayerMouseEvent } from 'maplibre-gl';
import type { 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';
export class SplitControls {
map: Map;
map: maplibregl.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: Map, layerEventManager: MapLayerEventManager) {
constructor(map: maplibregl.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: MapLayerMouseEvent) {
layerOnClick(e: maplibregl.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 { Marker } from 'maplibre-gl';
import maplibregl from 'maplibre-gl';
import { getSvgForSymbol } from '$lib/components/map/gpx-layer/gpx-layer';
let props: {
@@ -41,7 +41,7 @@
})
);
let marker: Marker | null = null;
let marker: maplibregl.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 Marker({
marker = new maplibregl.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>.
You can learn more about its origin and accuracy in the <a href="https://mapterhorn.com/attribution/" target="_blank">documentation</a>.
Mehr über die Herkunft und Genauigkeit erfährst du in der <a href="https://mapterhorn.com/attribution/" target="_blank">Dokumentation</a>.
</DocsNote>
+2 -2
View File
@@ -13,8 +13,8 @@ title: Integrazioa
Behar duzun guztia hau da:
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.
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.
Ondoren, konfiguratzailearekin jolastu dezakezu zure mapa pertsonalizatzeko eta dagokion HTML kodea sortzeko.
+2 -2
View File
@@ -59,7 +59,7 @@ Maparen geruzen botoiak mapa-oinarri desberdinen artean aldatzeko aukera ematen
<DocsLayers />
<span class="text-sm text-center mt-2">
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.
Pasa ezazu maparen gainean <a href="https://hiking.waymarkedtrails.org" target="_blank">markatutako mendi-ibiliak</a> gainjartzeko oinarrizko mapa topografikoaren gainean.
</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.
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.
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.
+2 -3
View File
@@ -48,7 +48,6 @@ Maparen orientazioa eta okertzea kontrolatzeko, mapa ere arrasta dezakezu <kbd>
</DocsNote>
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Full screen
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Pantaila osoa
Enter or exit full screen mode.
You can also press <kbd>F11</kbd> to toggle, or <kbd>Escape</kbd> to exit.
Sartu edo irten pantaila osoko moduan.<kbd>F11</kbd> ere saka dezakezu txandakatzeko, edo <kbd>Ihes</kbd> irteteko.
@@ -18,7 +18,7 @@ Tresna honen bidez elebazio datuak gehitzen ahal dira ibilbidetan eta [interesgu
<DocsNote>
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>.
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>.
</DocsNote>
+2 -2
View File
@@ -18,8 +18,8 @@ Tresna hau erabiltzeko [hautatu](../files-and-stats) behar duzu hainbat fitxateg
<DocsNote>
Selected items are merged in the order they appear in the files list.
Reorder items by drag-and-drop if needed.
Hautatutako elementuak fitxategien zerrendan agertzen diren ordenan batzen dira.
Berrantolatu elementuak arrastatu eta jareginez, behar izanez gero.
</DocsNote>
@@ -10,7 +10,7 @@ title: Stijging
# <MountainSnow size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
Met dit gereedschap kun je hoogtegegevens toevoegen aan sporen en [interessante punten](../gpx), of de bestaande gegevens vervangen.
Met deze tool kunt u hoogtegegevens toevoegen aan sporen en [punten van belang](../gpx) of de bestaande gegevens vervangen.
<div class="flex flex-row justify-center">
<Elevation class="text-foreground p-3 border rounded-md shadow-lg" />
+1 -1
View File
@@ -71,7 +71,7 @@ title: Планирование и редактирование маршрута
Изменить направление маршрута на противоположное.
### <House size="16" class="inline-block" style="margin-bottom: 2px" /> Back to start
### <House size="16" class="inline-block" style="margin-bottom: 2px" /> Вернуться в начало
Подсоедините последнюю точку маршрута к начальной точке, используя выбранные параметры маршрутизации.
@@ -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>
+1 -1
View File
@@ -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
+21 -21
View File
@@ -1,5 +1,5 @@
---
title: View options
title: 檢視選項
---
<script lang="ts">
@@ -9,38 +9,38 @@ title: View options
# { title }
This menu provides options to rearrange the interface and the map view.
此選單提供重新排列介面與地圖檢視方式的選項。
### <ChartArea size="16" class="inline-block" style="margin-bottom: 2px" /> Elevation profile
### <ChartArea size="16" class="inline-block" style="margin-bottom: 2px" /> 高度剖面圖
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" /> File tree
### <ListTree size="16" class="inline-block" style="margin-bottom: 2px" /> 檔案樹狀結構
Toggle the tree layout for the [file list](../files-and-stats).
切換[檔案清單](../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.
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.
此外,檔案樹狀檢視可讓你透過可收合的區段,查看檔案中包含的[軌跡、區段和興趣點](../gpx)。
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> 切換至上一個底圖
Change the basemap to the one previously selected through the [map layer control](../map-controls).
將底圖變更為先前透過[地圖圖層控制項](../map-controls)選取的底圖。
### <Layers2 size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle overlays
### <Layers2 size="16" class="inline-block" style="margin-bottom: 2px" /> 切換疊加圖層
Toggle the visibility of the map overlays selected through the [map layer control](../map-controls).
切換透過[地圖圖層控制項](../map-controls)選取之地圖疊加圖層的顯示狀態。
### <Coins size="16" class="inline-block" style="margin-bottom: 2px" /> Distance markers
### <Coins size="16" class="inline-block" style="margin-bottom: 2px" /> 距離標記
Toggle the visibility of distance markers on the map.
They are displayed for the current selection, like the [elevation profile](../files-and-stats).
切換地圖上距離標記的顯示狀態。
距離標記會針對目前的選取內容顯示,就像[高度剖面圖](../files-and-stats)一樣。
### <Milestone size="16" class="inline-block" style="margin-bottom: 2px" /> Direction arrows
### <Milestone size="16" class="inline-block" style="margin-bottom: 2px" /> 方向箭頭
Toggle the visibility of direction arrows on the map.
切換地圖上方向箭頭的顯示狀態。
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> 切換 3D
Enter or exit the 3D map view.
進入或離開 3D 地圖檢視。
<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" /> Full screen
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> 全螢幕
Enter or exit full screen mode.
You can also press <kbd>F11</kbd> to toggle, or <kbd>Escape</kbd> to exit.
進入或離開全螢幕模式。
你也可以按下 <kbd>F11</kbd> 來切換,或按下 <kbd>Escape</kbd> 離開。
+4 -4
View File
@@ -1,6 +1,6 @@
import { get } from 'svelte/store';
import { selection } from '$lib/logic/selection';
import { LngLatBounds } from 'maplibre-gl';
import maplibregl 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: LngLatBounds = new LngLatBounds();
private _bounds: maplibregl.LngLatBounds = new maplibregl.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 LngLatBounds([180, 90, -180, -90]);
this._bounds = new maplibregl.LngLatBounds([180, 90, -180, -90]);
}
centerMapOnSelection() {
let selected = get(selection).getSelected();
let bounds = new LngLatBounds();
let bounds = new maplibregl.LngLatBounds();
if (selected.find((item) => item instanceof ListWaypointItem)) {
selection.applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
+6 -6
View File
@@ -1,16 +1,16 @@
import { ListItem, ListLevel } from '$lib/components/file-list/file-list';
import { GPXFile, GPXStatistics, GPXStatisticsGroup, type Track } from 'gpx';
import { LngLatBounds } from 'maplibre-gl';
import maplibregl from 'maplibre-gl';
export class GPXStatisticsTree {
level: ListLevel;
statistics: {
[key: string]: GPXStatisticsTree | GPXStatistics;
} = {};
wptBounds: LngLatBounds;
wptBounds: maplibregl.LngLatBounds;
constructor(element: GPXFile | Track) {
this.wptBounds = new LngLatBounds();
this.wptBounds = new maplibregl.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: LngLatBounds): boolean {
intersectsBBox(bounds: maplibregl.LngLatBounds): boolean {
for (let key in this.statistics) {
const stats = this.statistics[key];
if (stats instanceof GPXStatistics) {
const bbox = new LngLatBounds(
const bbox = new maplibregl.LngLatBounds(
stats.global.bounds.southWest,
stats.global.bounds.northEast
);
@@ -67,7 +67,7 @@ export class GPXStatisticsTree {
return false;
}
intersectsWaypointBBox(bounds: LngLatBounds): boolean {
intersectsWaypointBBox(bounds: maplibregl.LngLatBounds): boolean {
return !this.wptBounds.isEmpty() && this.wptBounds.intersects(bounds);
}
}
+4 -4
View File
@@ -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 { Map as MapLibreMap, LngLatBounds } from 'maplibre-gl';
import maplibregl 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 LngLatBounds(southWest, northEast);
let bounds = new maplibregl.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 LngLatBounds();
let bbox = new maplibregl.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: MapLibreMap, id: string, svg: string, size: number = 100) {
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string, size: number = 100) {
if (!map.hasImage(id)) {
let icon = new Image(size, size);
icon.onload = () => {
+2 -2
View File
@@ -163,7 +163,7 @@
"path": "Sendero",
"pedestrian": "Peatonal",
"cycleway": "Ciclovía",
"steps": "Escalones",
"steps": "Pasos",
"road": "Carretera",
"bridleway": "Ruta ecuestre",
"platform": "Plataforma",
@@ -230,7 +230,7 @@
"extract": {
"tooltip": "Extraer contenidos en elementos separados",
"button": "Extraer",
"help": "Al extraer los contenidos de los elementos seleccionados creará un elemento separado para cada uno.",
"help": "La extracción del contenido de los elementos seleccionados creará un elemento separado para cada uno de sus contenidos.",
"help_invalid_selection": "Su selección debe contener elementos con múltiples trazas para extraerlos."
},
"elevation": {
+1 -1
View File
@@ -20,7 +20,7 @@
"export": "Exporteren...",
"export_all": "Alles exporteren...",
"export_options": "Exporteer instellingen",
"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_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_button": "Help de website gratis te houden",
"download_file": "Bestand downloaden",
"download_files": "Bestanden downloaden",
+3 -3
View File
@@ -64,7 +64,7 @@
"ctrl": "Ctrl",
"click": "Clique",
"drag": "Arrastar",
"right_click_drag": "Right-click drag",
"right_click_drag": "Clique direito arraste",
"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": "Create and edit points of interest",
"tooltip": "Criar ponto de interesse",
"icon": "Icon",
"link": "Link",
"longitude": "Longitude",