mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 23:53:25 +00:00
switch to mapbox gl
This commit is contained in:
2
todo
2
todo
@@ -1,2 +0,0 @@
|
|||||||
- state management with https://immerjs.github.io/immer/
|
|
||||||
- map with MapLibre
|
|
1258
website/package-lock.json
generated
1258
website/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -39,12 +39,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.5.2",
|
"@fortawesome/free-brands-svg-icons": "^6.5.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||||
"@maplibre/maplibre-gl-geocoder": "^1.5.0",
|
"@mapbox/mapbox-gl-geocoder": "^5.0.2",
|
||||||
"bits-ui": "^0.21.2",
|
"bits-ui": "^0.21.2",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"gpx": "file:../gpx",
|
"gpx": "file:../gpx",
|
||||||
"lucide-svelte": "^0.365.0",
|
"lucide-svelte": "^0.365.0",
|
||||||
"maplibre-gl": "^4.1.2",
|
"mapbox-gl": "^3.2.0",
|
||||||
"svelte-fa": "^4.0.2",
|
"svelte-fa": "^4.0.2",
|
||||||
"tailwind-merge": "^2.2.2",
|
"tailwind-merge": "^2.2.2",
|
||||||
"tailwind-variants": "^0.2.1"
|
"tailwind-variants": "^0.2.1"
|
||||||
|
@@ -1,86 +1,103 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
|
|
||||||
import maplibregl from 'maplibre-gl';
|
import mapboxgl from 'mapbox-gl';
|
||||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||||
|
|
||||||
import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder';
|
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
|
||||||
import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css';
|
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
|
||||||
|
|
||||||
export let map: maplibregl.Map | null = null;
|
mapboxgl.accessToken =
|
||||||
|
'pk.eyJ1IjoiZ3B4c3R1ZGlvIiwiYSI6ImNrdHVoM2pjNTBodmUycG1yZTNwcnJ3MzkifQ.YZnNs9s9oCQPzoXAWs_SLg';
|
||||||
|
|
||||||
|
let map: mapboxgl.Map | null = null;
|
||||||
|
|
||||||
|
export let distanceUnits: 'metric' | 'imperial' = 'metric';
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
map = new maplibregl.Map({
|
map = new mapboxgl.Map({
|
||||||
container: 'map',
|
container: 'map',
|
||||||
style: 'https://demotiles.maplibre.org/style.json'
|
style: 'mapbox://styles/mapbox/outdoors-v12',
|
||||||
|
projection: 'mercator',
|
||||||
|
hash: true,
|
||||||
|
language: 'auto',
|
||||||
|
attributionControl: false,
|
||||||
|
logoPosition: 'bottom-right'
|
||||||
});
|
});
|
||||||
|
|
||||||
map.addControl(
|
map.addControl(
|
||||||
new maplibregl.NavigationControl({
|
new mapboxgl.AttributionControl({
|
||||||
showCompass: false
|
compact: true
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
map.addControl(
|
map.addControl(new mapboxgl.NavigationControl());
|
||||||
new maplibregl.GeolocateControl({
|
|
||||||
positionOptions: {
|
|
||||||
enableHighAccuracy: true
|
|
||||||
},
|
|
||||||
trackUserLocation: true
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const geocoderApi = {
|
|
||||||
forwardGeocode: async (config) => {
|
|
||||||
const features = [];
|
|
||||||
try {
|
|
||||||
const request = `https://nominatim.openstreetmap.org/search?q=${config.query}&format=geojson&polygon_geojson=1&addressdetails=1`;
|
|
||||||
const response = await fetch(request);
|
|
||||||
const geojson = await response.json();
|
|
||||||
for (const feature of geojson.features) {
|
|
||||||
const center = [
|
|
||||||
feature.bbox[0] + (feature.bbox[2] - feature.bbox[0]) / 2,
|
|
||||||
feature.bbox[1] + (feature.bbox[3] - feature.bbox[1]) / 2
|
|
||||||
];
|
|
||||||
const point = {
|
|
||||||
type: 'Feature',
|
|
||||||
geometry: {
|
|
||||||
type: 'Point',
|
|
||||||
coordinates: center
|
|
||||||
},
|
|
||||||
place_name: feature.properties.display_name,
|
|
||||||
properties: feature.properties,
|
|
||||||
text: feature.properties.display_name,
|
|
||||||
place_type: ['place'],
|
|
||||||
center
|
|
||||||
};
|
|
||||||
features.push(point);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Failed to forwardGeocode with error: ${e}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
features
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
map.addControl(
|
map.addControl(
|
||||||
new MaplibreGeocoder(geocoderApi, {
|
new MapboxGeocoder({
|
||||||
maplibregl,
|
accessToken: mapboxgl.accessToken,
|
||||||
|
mapboxgl: mapboxgl,
|
||||||
collapsed: true
|
collapsed: true
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
onDestroy(() => {
|
map.addControl(
|
||||||
if (map) {
|
new mapboxgl.GeolocateControl({
|
||||||
map.remove();
|
positionOptions: {
|
||||||
}
|
enableHighAccuracy: true
|
||||||
|
},
|
||||||
|
trackUserLocation: true,
|
||||||
|
showUserHeading: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
map.addControl(
|
||||||
|
new mapboxgl.ScaleControl({
|
||||||
|
unit: distanceUnits
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div {...$$restProps}>
|
<div {...$$restProps}>
|
||||||
<div id="map" class="h-full"></div>
|
<div id="map" class="h-full"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
div :global(.mapboxgl-ctrl) {
|
||||||
|
@apply shadow-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.mapboxgl-ctrl-geocoder) {
|
||||||
|
@apply flex;
|
||||||
|
@apply flex-row;
|
||||||
|
@apply w-fit;
|
||||||
|
@apply min-w-fit;
|
||||||
|
@apply items-center;
|
||||||
|
@apply shadow-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.suggestions) {
|
||||||
|
@apply shadow-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.mapboxgl-ctrl-geocoder--icon-search) {
|
||||||
|
@apply fill-inherit;
|
||||||
|
@apply relative;
|
||||||
|
@apply top-0;
|
||||||
|
@apply left-0;
|
||||||
|
@apply my-2;
|
||||||
|
@apply w-[29px];
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.mapboxgl-ctrl-geocoder--input) {
|
||||||
|
@apply relative;
|
||||||
|
@apply py-0;
|
||||||
|
@apply pl-2;
|
||||||
|
@apply focus:outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div :global(.mapboxgl-ctrl-geocoder--collapsed .mapboxgl-ctrl-geocoder--input) {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -11,7 +11,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="absolute top-2 left-0 right-0 z-10 flex flex-row justify-center pointer-events-none">
|
<div class="absolute top-2 left-0 right-0 z-10 flex flex-row justify-center pointer-events-none">
|
||||||
<div class="w-fit flex flex-row items-center p-1 bg-background rounded-md pointer-events-auto">
|
<div
|
||||||
|
class="w-fit flex flex-row items-center p-1 bg-background rounded-md pointer-events-auto shadow-md"
|
||||||
|
>
|
||||||
<Logo class="h-5 mt-0.5 mx-2" />
|
<Logo class="h-5 mt-0.5 mx-2" />
|
||||||
<Menubar.Root class="border-none h-fit p-0">
|
<Menubar.Root class="border-none h-fit p-0">
|
||||||
<Menubar.Menu>
|
<Menubar.Menu>
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="absolute top-0 bottom-0 left-0 z-10 flex flex-col justify-center pointer-events-none">
|
<div class="absolute top-0 bottom-0 left-0 z-10 flex flex-col justify-center pointer-events-none">
|
||||||
<div class="flex flex-col p-1 space-y-1 bg-background rounded-md pointer-events-auto">
|
<div class="flex flex-col p-1 space-y-1 bg-background rounded-md pointer-events-auto shadow-md">
|
||||||
<ToolbarItem>
|
<ToolbarItem>
|
||||||
<Fa slot="icon" icon={faPencil} />
|
<Fa slot="icon" icon={faPencil} />
|
||||||
<span slot="tooltip">Edit the track points</span>
|
<span slot="tooltip">Edit the track points</span>
|
||||||
|
Reference in New Issue
Block a user