route full support

This commit is contained in:
vcoppe committed 2026-10-26 18:51:56 +01:00
1 parent c842da8dc1
commit b6c0f5190a
91 files changed
+2523 -847

No files matched your search

+5
View File
@@ -18,6 +18,11 @@ pub fn style(color: Option<String>, opacity: Option<f64>, width: Option<f64>) ->
run(|e| api::style(e, color.as_deref(), opacity, width))
}
#[wasm_bindgen]
pub fn new_route() -> Outcome {
run(api::new_route)
}
#[wasm_bindgen]
pub fn new_track() -> Outcome {
run(api::new_track)
+1 -5
View File
@@ -45,10 +45,8 @@ pub fn selection_statistics() -> GlobalStatistics {
}
/// A file as GPX (UTF-8 bytes), `undefined` if it does not exist. The options say which data of the trackpoints
/// to keep, and with `as_route` that the segments are written as routes (`rte`) instead of tracks:
/// the anchors are the route points, and the trackpoints between them the points of their path.
/// to keep.
#[wasm_bindgen]
#[allow(clippy::too_many_arguments)]
pub fn export_file(
file_id: &str,
time: bool,
@@ -57,7 +55,6 @@ pub fn export_file(
atemp: bool,
power: bool,
osm: bool,
as_route: bool,
) -> Option<Vec<u8>> {
let id = parse_uuid(file_id)?;
let options = ExportOptions {
@@ -67,7 +64,6 @@ pub fn export_file(
atemp,
power,
osm,
as_route,
};
with_engine(|e| api::export_file(e, id, options)).flatten()
}
+8
View File
@@ -41,6 +41,14 @@ pub fn arrow_select(down: bool, add: bool) -> Outcome {
// with the selection when it holds elements of the same kind in the same place (same file, same
// track for segments), otherwise they replace it.
#[wasm_bindgen]
pub fn select_routes(file_id: &str, route_ids_bytes: &[u8], mode: SelectMode) -> Outcome {
match parse_uuid(file_id).zip(uuid_list(route_ids_bytes)) {
Some((file_id, ids)) => run(|e| api::select_routes(e, file_id, &ids, mode.into())),
None => fail("the ids are not UUIDs"),
}
}
#[wasm_bindgen]
pub fn select_tracks(file_id: &str, track_ids_bytes: &[u8], mode: SelectMode) -> Outcome {
match parse_uuid(file_id).zip(uuid_list(track_ids_bytes)) {
+10 -14
View File
@@ -16,6 +16,7 @@ use crate::types::*;
const SIMPLE: &[u8] = include_bytes!("../../gpx-rs/data/simple.gpx");
const WITH_TIME: &[u8] = include_bytes!("../../gpx-rs/data/with_time.gpx");
const WITH_SURFACE: &[u8] = include_bytes!("../../gpx-rs/data/with_surface.gpx");
const WITH_ROUTES: &[u8] = include_bytes!("../../gpx-rs/data/with_routes.gpx");
thread_local! {
static LAST: std::cell::RefCell<JsValue> = const { std::cell::RefCell::new(JsValue::UNDEFINED) };
@@ -112,10 +113,7 @@ fn test_unknown_file_has_no_structure() {
assert!(crate::queries::files::file_structure(&id).is_undefined());
assert!(crate::queries::files::file_structure("not an id").is_undefined());
assert!(crate::queries::files::file_statistics(&id).is_undefined());
assert!(
crate::queries::files::export_file(&id, true, true, true, true, true, true, false)
.is_none()
);
assert!(crate::queries::files::export_file(&id, true, true, true, true, true, true).is_none());
assert_eq!(
crate::queries::coordinates::segment_coordinates(&id).length(),
0
@@ -279,8 +277,7 @@ fn test_export_and_exportable_data() {
let ids = order();
let bytes =
crate::queries::files::export_file(&ids[0], true, true, true, true, true, true, false)
.unwrap();
crate::queries::files::export_file(&ids[0], true, true, true, true, true, true).unwrap();
assert!(String::from_utf8(bytes).unwrap().contains("<gpx"));
// the time is the first bit
@@ -300,18 +297,17 @@ fn test_export_and_exportable_data() {
}
#[wasm_bindgen_test]
fn test_export_as_route() {
started_with(&[(SIMPLE, "plain")]);
let id = order().remove(0);
let text = |as_route| {
fn test_export_tracks_and_routes() {
started_with(&[(SIMPLE, "track"), (WITH_ROUTES, "routes")]);
let text = |id: &str| {
let bytes =
crate::queries::files::export_file(&id, true, true, true, true, true, true, as_route)
.unwrap();
crate::queries::files::export_file(id, true, true, true, true, true, true).unwrap();
String::from_utf8(bytes).unwrap()
};
let tracks = text(false);
let ids = order();
let tracks = text(&ids[0]);
assert!(tracks.contains("<trk>") && !tracks.contains("<rte>"));
let routes = text(true);
let routes = text(&ids[1]);
assert!(routes.contains("<rte>") && !routes.contains("<trk>"));
assert!(routes.contains("<rtept"));
}
+18 -5
View File
@@ -28,16 +28,19 @@ const FILE_STRUCTURE_TS: &str = r#"
export type Selection =
| { type: 'empty' }
| { type: 'file'; fileIds: string[] }
| { type: 'route'; fileId: string; routeIds: string[] }
| { type: 'track'; fileId: string; trackIds: string[] }
| { type: 'segment'; fileId: string; trackId: string; segmentIds: string[] }
| { type: 'waypoints'; fileId: string }
| { type: 'waypoint'; fileId: string; waypointIds: string[] };
/**
* Where moved elements go: a list of the file tree and the position in it, counted among the
* elements of the list that are not moved.
* elements of the list that are not moved. Routes and tracks keep their kind: moved among the
* other kind, routes go after the routes, tracks before the tracks.
*/
export type MoveTarget =
| { type: 'files'; index: number }
| { type: 'routes'; fileId: string; index: number }
| { type: 'tracks'; fileId: string; index: number }
| { type: 'segments'; fileId: string; trackId: string; index: number }
| { type: 'waypoints'; fileId: string; index: number };
@@ -83,7 +86,7 @@ export interface SelectionPoint {
}
/** What was copied or cut, to be pasted: the kind of the elements and their ids. */
export interface Clipboard {
type: 'files' | 'tracks' | 'segments' | 'waypoints';
type: 'files' | 'routes' | 'tracks' | 'segments' | 'waypoints';
ids: string[];
cut: boolean;
}
@@ -119,6 +122,8 @@ export interface FileStructure {
id: string;
name: string;
desc?: string;
/** The routes come before the tracks, in the file and in the statistics. */
routes: RouteNode[];
tracks: TrackNode[];
waypoints: WaypointNode[];
/** Changes when the waypoints of the file change: refetch their coordinates. */
@@ -146,14 +151,22 @@ export interface GlobalStatistics {
/** Absent when there are no trackpoints. */
bounds?: { west: number; south: number; east: number; north: number };
}
export interface TrackNode {
id: string;
/** The name, description and style of a route or a track. */
export interface PathInfo {
name?: string;
desc?: string;
/** Style of the track, only present when the file defines it. */
/** Style, only present when the file defines it. */
color?: string;
opacity?: number;
width?: number;
}
/** A route: like a track, with a single segment. */
export interface RouteNode extends PathInfo {
id: string;
segment: SegmentNode;
}
export interface TrackNode extends PathInfo {
id: string;
segments: SegmentNode[];
}
export interface SegmentNode {
+2
View File
@@ -15,6 +15,7 @@ pub enum MergeType {
#[derive(Clone, Copy)]
pub enum SplitType {
Files,
Routes,
Tracks,
Segments,
}
@@ -23,6 +24,7 @@ impl From<SplitType> for engine::SplitType {
fn from(t: SplitType) -> Self {
match t {
SplitType::Files => Self::Files,
SplitType::Routes => Self::Routes,
SplitType::Tracks => Self::Tracks,
SplitType::Segments => Self::Segments,
}