mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-01 08:12:32 +00:00
progress
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Data from '$lib/components/Data.svelte';
|
||||
import GPXMapLayers from '$lib/components/GPXMapLayers.svelte';
|
||||
import ElevationProfile from '$lib/components/ElevationProfile.svelte';
|
||||
import FileList from '$lib/components/FileList.svelte';
|
||||
import GPXData from '$lib/components/GPXData.svelte';
|
||||
@@ -15,7 +15,7 @@
|
||||
<Toolbar />
|
||||
<Map class="h-full" />
|
||||
<LayerControl />
|
||||
<Data />
|
||||
<GPXMapLayers />
|
||||
<FileList />
|
||||
</div>
|
||||
<div class="h-60 flex flex-row gap-2 overflow-hidden border">
|
||||
|
@@ -6,7 +6,8 @@
|
||||
import Chart from 'chart.js/auto';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
|
||||
import { map, fileCollection, fileOrder, selectedFiles, settings } from '$lib/stores';
|
||||
import { map, fileOrder, selectedFiles, settings } from '$lib/stores';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import {
|
||||
@@ -230,9 +231,8 @@
|
||||
|
||||
$: if (chart && $settings) {
|
||||
let gpxFiles = new GPXFiles(Array.from($selectedFiles));
|
||||
let order = $fileOrder.length == 0 ? $fileCollection.files : $fileOrder;
|
||||
gpxFiles.files.sort(function (a, b) {
|
||||
return order.indexOf(a) - order.indexOf(b);
|
||||
return get(fileOrder).indexOf(a) - get(fileOrder).indexOf(b);
|
||||
});
|
||||
|
||||
// update data
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import GPX from './GPX.svelte';
|
||||
import GPXMapLayer from './GPXMapLayer.svelte';
|
||||
|
||||
import { fileCollection } from '$lib/stores';
|
||||
</script>
|
||||
|
||||
{#each $fileCollection.files as file}
|
||||
<GPX {file} />
|
||||
<GPXMapLayer {file} />
|
||||
{/each}
|
@@ -7,8 +7,8 @@
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { CircleHelp } from 'lucide-svelte';
|
||||
|
||||
import { map, selectedFiles } from '$lib/stores';
|
||||
import { AnchorPointHierarchy, getMarker } from './routing';
|
||||
import { map, selectedFiles, fileCollection } from '$lib/stores';
|
||||
import { AnchorPointHierarchy, getMarker, route } from './routing';
|
||||
import { onDestroy } from 'svelte';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
import KDBush from 'kdbush';
|
||||
@@ -17,22 +17,23 @@
|
||||
|
||||
import { _ } from 'svelte-i18n';
|
||||
|
||||
let routingProfile = {
|
||||
value: 'bike',
|
||||
label: 'bike'
|
||||
};
|
||||
let brouterProfiles = {
|
||||
let brouterProfiles: { [key: string]: string } = {
|
||||
bike: 'Trekking-dry',
|
||||
racingBike: 'fastbike',
|
||||
mountainBike: 'MTB',
|
||||
racing_bike: 'fastbike',
|
||||
mountain_bike: 'MTB',
|
||||
foot: 'Hiking-Alpine-SAC6',
|
||||
motorcycle: 'Car-FastEco',
|
||||
water: 'river',
|
||||
railway: 'rail'
|
||||
};
|
||||
let routingProfile = {
|
||||
value: 'bike',
|
||||
label: $_('toolbar.routing.activities.bike')
|
||||
};
|
||||
let routing = true;
|
||||
let privateRoads = false;
|
||||
|
||||
let anchorPointHierarchy: AnchorPointHierarchy | null = null;
|
||||
let markers: mapboxgl.Marker[] = [];
|
||||
let file: GPXFile | null = null;
|
||||
let kdbush: KDBush | null = null;
|
||||
@@ -50,8 +51,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
function extendFile(e: mapboxgl.MapMouseEvent) {
|
||||
console.log(e.lngLat);
|
||||
async function extendFile(e: mapboxgl.MapMouseEvent) {
|
||||
if (file && anchorPointHierarchy && anchorPointHierarchy.points.length > 0) {
|
||||
let lastPoint = anchorPointHierarchy.points[anchorPointHierarchy.points.length - 1];
|
||||
let newPoint = {
|
||||
lon: e.lngLat.lng,
|
||||
lat: e.lngLat.lat
|
||||
};
|
||||
let response = await route(
|
||||
[lastPoint.point.getCoordinates(), newPoint],
|
||||
brouterProfiles[routingProfile.value],
|
||||
privateRoads,
|
||||
routing
|
||||
);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
|
||||
let insertableMarker: mapboxgl.Marker | null = null;
|
||||
@@ -107,12 +121,12 @@
|
||||
file = $selectedFiles.values().next().value;
|
||||
// record time
|
||||
let start = performance.now();
|
||||
let anchorPoints = AnchorPointHierarchy.create(file);
|
||||
anchorPointHierarchy = AnchorPointHierarchy.create(file);
|
||||
// record time
|
||||
let end = performance.now();
|
||||
console.log('Time to create anchor points: ' + (end - start) + 'ms');
|
||||
|
||||
markers = anchorPoints.getMarkers();
|
||||
markers = anchorPointHierarchy.getMarkers();
|
||||
|
||||
toggleMarkersForZoomLevelAndBounds();
|
||||
$map.on('zoom', toggleMarkersForZoomLevelAndBounds);
|
||||
@@ -150,7 +164,9 @@
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each Object.keys(brouterProfiles) as profile}
|
||||
<Select.Item value={profile}>{profile}</Select.Item>
|
||||
<Select.Item value={profile}
|
||||
>{$_(`toolbar.routing.activities.${profile}`)}</Select.Item
|
||||
>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import type { Coordinates, GPXFile, TrackPoint } from "gpx";
|
||||
import type { Coordinates, GPXFile } from "gpx";
|
||||
import { TrackPoint } from "gpx";
|
||||
import mapboxgl from "mapbox-gl";
|
||||
|
||||
export function getMarker(coordinates: Coordinates, draggable: boolean = false): mapboxgl.Marker {
|
||||
@@ -13,23 +14,18 @@ export function getMarker(coordinates: Coordinates, draggable: boolean = false):
|
||||
export type SimplifiedTrackPoint = { point: TrackPoint, index: number, distance?: number, segment?: number, zoom?: number };
|
||||
|
||||
export class AnchorPointHierarchy {
|
||||
points: SimplifiedTrackPoint[][];
|
||||
points: SimplifiedTrackPoint[];
|
||||
|
||||
constructor() {
|
||||
this.points = [];
|
||||
for (let i = 0; i <= 20; i++) {
|
||||
this.points.push([]);
|
||||
}
|
||||
}
|
||||
|
||||
getMarkers(): mapboxgl.Marker[] {
|
||||
let markers = [];
|
||||
for (let points of this.points) {
|
||||
for (let point of points) {
|
||||
let marker = getMarker(point.point.getCoordinates(), true);
|
||||
Object.defineProperty(marker, '_simplified', { value: point });
|
||||
markers.push(marker);
|
||||
}
|
||||
for (let point of this.points) {
|
||||
let marker = getMarker(point.point.getCoordinates(), true);
|
||||
Object.defineProperty(marker, '_simplified', { value: point });
|
||||
markers.push(marker);
|
||||
}
|
||||
return markers;
|
||||
}
|
||||
@@ -46,7 +42,7 @@ export class AnchorPointHierarchy {
|
||||
simplified.forEach((point) => {
|
||||
point.segment = s;
|
||||
point.zoom = getZoomLevelForDistance(point.point.getLatitude(), point.distance);
|
||||
hierarchy.points[point.zoom].push(point);
|
||||
hierarchy.points.push(point);
|
||||
});
|
||||
s++;
|
||||
}
|
||||
@@ -158,19 +154,39 @@ function bearing(latA: number, lonA: number, latB: number, lonB: number): number
|
||||
Math.cos(latA) * Math.sin(latB) - Math.sin(latA) * Math.cos(latB) * Math.cos(lonB - lonA));
|
||||
}
|
||||
|
||||
export function route(points: TrackPoint[], brouterProfile: string, privateRoads: boolean, routing: boolean) {
|
||||
export function route(points: Coordinates[], brouterProfile: string, privateRoads: boolean, routing: boolean): Promise<TrackPoint[]> {
|
||||
if (routing) {
|
||||
getRoute(points, brouterProfile, privateRoads).then(response => {
|
||||
return response.json();
|
||||
});
|
||||
return getRoute(points, brouterProfile, privateRoads);
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
resolve(points);
|
||||
resolve(points.map(point => new TrackPoint({
|
||||
attributes: {
|
||||
lat: point.lat,
|
||||
lon: point.lon
|
||||
}
|
||||
})));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getRoute(points: TrackPoint[], brouterProfile: string, privateRoads: boolean): Promise<Response> {
|
||||
let url = `https://routing.gpx.studio?profile=${brouterProfile + privateRoads ? '-private' : ''}&lonlats=${points.map(point => `${point.getLongitude()},${point.getLatitude()}`).join('|')}&format=geojson&alternativeidx=0`;
|
||||
return fetch(url);
|
||||
async function getRoute(points: Coordinates[], brouterProfile: string, privateRoads: boolean): Promise<TrackPoint[]> {
|
||||
let url = `https://routing.gpx.studio?lonlats=${points.map(point => `${point.lon},${point.lat}`).join('|')}&profile=${brouterProfile + (privateRoads ? '-private' : '')}&format=geojson&alternativeidx=0`;
|
||||
|
||||
let response = await fetch(url);
|
||||
let geojson = await response.json();
|
||||
|
||||
let route: TrackPoint[] = [];
|
||||
let coordinates = geojson.features[0].geometry.coordinates;
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
let coord = coordinates[i];
|
||||
route.push(new TrackPoint({
|
||||
attributes: {
|
||||
lat: coord[1],
|
||||
lon: coord[0]
|
||||
},
|
||||
ele: coord[2] ?? undefined
|
||||
}));
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
@@ -33,7 +33,16 @@
|
||||
"allow_private": "Allow private roads",
|
||||
"help_no_file": "Select a file to use the routing tool, or create a new file from the menu",
|
||||
"help_multiple_files": "Select a single file to use the routing tool",
|
||||
"help": "Click on the map to add a new point, or drag existing points to change the route"
|
||||
"help": "Click on the map to add a new point, or drag existing points to change the route",
|
||||
"activities": {
|
||||
"bike": "Bike",
|
||||
"racing_bike": "Racing bike",
|
||||
"mountain_bike": "Mountain bike",
|
||||
"foot": "Run/hike",
|
||||
"motorcycle": "Motorcycle",
|
||||
"water": "Water",
|
||||
"railway": "Railway"
|
||||
}
|
||||
},
|
||||
"time_tooltip": "Change the time and speed data",
|
||||
"reverse_tooltip": "Reverse the direction",
|
||||
|
Reference in New Issue
Block a user