mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-09-24 08:27:37 +00:00
wasm first steps
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
target/
|
||||
pkg/
|
||||
Generated
+114
@@ -0,0 +1,114 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "gpx-rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "gpx-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
@@ -0,0 +1,27 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::{stack::Stack, types::GPXFile};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Controller {
|
||||
stack: Stack,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Controller {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stack: Stack::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn create_file(&mut self, name: &str) {
|
||||
let id = self.stack.get_new_file_id();
|
||||
let file = Rc::new(GPXFile::new(id, name));
|
||||
self.stack.update(&[file]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
mod controller;
|
||||
mod stack;
|
||||
mod types;
|
||||
@@ -0,0 +1,101 @@
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use crate::types::{GPXFile, GPXFileId};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stack {
|
||||
entries: Vec<StackEntry>,
|
||||
index: Option<usize>,
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn current(&self) -> Option<&StackEntry> {
|
||||
match self.index {
|
||||
Some(i) => Some(&self.entries[i]),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_new_file_id(&self) -> GPXFileId {
|
||||
if let Some(current) = self.current() {
|
||||
for id in 0..current.len() {
|
||||
if !current.contains_key(&id) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
current.len() as GPXFileId
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, files: &[Rc<GPXFile>]) {
|
||||
let mut next = match self.current() {
|
||||
Some(current) => current.clone(),
|
||||
None => StackEntry::default(),
|
||||
};
|
||||
for file in files {
|
||||
next.insert(file.id, file.clone());
|
||||
}
|
||||
self.push(next);
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, files: &[GPXFileId]) {
|
||||
if let Some(current) = self.current() {
|
||||
let mut next = current.clone();
|
||||
for file in files {
|
||||
next.remove(file);
|
||||
}
|
||||
self.push(next);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_undo(&self) -> bool {
|
||||
self.index.is_some()
|
||||
}
|
||||
|
||||
pub fn can_redo(&self) -> bool {
|
||||
match self.index {
|
||||
Some(i) => i + 1 < self.entries.len(),
|
||||
None => !self.entries.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn undo(&mut self) {
|
||||
if let Some(i) = self.index {
|
||||
if i == 0 {
|
||||
self.index = None;
|
||||
} else {
|
||||
self.index = Some(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redo(&mut self) {
|
||||
match self.index {
|
||||
Some(i) => {
|
||||
if i + 1 < self.entries.len() {
|
||||
self.index = Some(i + 1);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if !self.entries.is_empty() {
|
||||
self.index = Some(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, entry: StackEntry) {
|
||||
if let Some(i) = self.index {
|
||||
if i + 1 < self.entries.len() {
|
||||
self.entries.truncate(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
self.entries.push(entry);
|
||||
self.index = Some(self.entries.len() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub type StackEntry = HashMap<GPXFileId, Rc<GPXFile>>;
|
||||
@@ -0,0 +1,106 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type GPXFileId = usize;
|
||||
|
||||
pub struct GPXFile {
|
||||
pub id: GPXFileId,
|
||||
pub info: Rc<GPXFileInfo>,
|
||||
pub trk: Vec<Track>,
|
||||
pub wpt: Vec<Rc<WaypointChunk>>,
|
||||
}
|
||||
|
||||
impl GPXFile {
|
||||
pub fn new(id: GPXFileId, name: &str) -> Self {
|
||||
Self {
|
||||
id,
|
||||
info: Rc::new(GPXFileInfo::new(name)),
|
||||
trk: Vec::new(),
|
||||
wpt: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GPXFileInfo {
|
||||
pub name: String,
|
||||
pub desc: Option<String>,
|
||||
pub author: Option<Author>,
|
||||
pub link: Option<Link>,
|
||||
pub time: Option<i64>,
|
||||
}
|
||||
|
||||
impl GPXFileInfo {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_owned(),
|
||||
desc: None,
|
||||
author: None,
|
||||
link: None,
|
||||
time: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Author {
|
||||
pub name: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub link: Option<Link>,
|
||||
}
|
||||
|
||||
pub struct Link {
|
||||
pub href: String,
|
||||
pub text: Option<String>,
|
||||
pub type_: Option<String>,
|
||||
}
|
||||
|
||||
pub struct Track {
|
||||
pub info: Rc<TrackInfo>,
|
||||
pub trkseg: Vec<TrackSegment>,
|
||||
}
|
||||
|
||||
pub struct TrackInfo {
|
||||
name: Option<String>,
|
||||
cmt: Option<String>,
|
||||
desc: Option<String>,
|
||||
src: Option<String>,
|
||||
link: Option<Link>,
|
||||
type_: Option<String>,
|
||||
color: Option<String>,
|
||||
opacity: Option<f64>,
|
||||
width: Option<f64>,
|
||||
}
|
||||
|
||||
pub struct TrackSegment {
|
||||
pub trkpt: Vec<Rc<TrackPointChunk>>,
|
||||
}
|
||||
|
||||
pub type TrackPointChunk = Vec<TrackPoint>;
|
||||
|
||||
pub struct TrackPoint {
|
||||
pub coordinates: LngLat,
|
||||
pub ele: f64,
|
||||
pub time: Option<i64>,
|
||||
pub hr: Option<u16>,
|
||||
pub cad: Option<u16>,
|
||||
pub power: Option<u16>,
|
||||
pub atemp: Option<i16>,
|
||||
// TODO OSM data? or store intervals at a higher level?
|
||||
}
|
||||
|
||||
pub type WaypointChunk = Vec<Waypoint>;
|
||||
|
||||
pub struct Waypoint {
|
||||
pub coordinates: LngLat,
|
||||
pub ele: f64,
|
||||
pub time: Option<i64>,
|
||||
pub name: Option<String>,
|
||||
pub cmt: Option<String>,
|
||||
pub desc: Option<String>,
|
||||
pub link: Option<Link>,
|
||||
pub sym: Option<String>,
|
||||
pub type_: Option<String>,
|
||||
}
|
||||
|
||||
pub struct LngLat {
|
||||
pub lng: f64,
|
||||
pub lat: f64,
|
||||
}
|
||||
Generated
+21
-1
@@ -17,6 +17,7 @@
|
||||
"dexie": "^4.0.11",
|
||||
"file-saver": "^2.0.5",
|
||||
"gpx": "file:../gpx",
|
||||
"gpx-rs": "file:../gpx-rs/pkg",
|
||||
"immer": "^10.1.1",
|
||||
"jszip": "^3.10.1",
|
||||
"mapillary-js": "^4.1.2",
|
||||
@@ -70,7 +71,8 @@
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vaul-svelte": "^1.0.0-next.7",
|
||||
"vite": "^6.3.5"
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-wasm": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"../gpx": {
|
||||
@@ -89,6 +91,10 @@
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
},
|
||||
"../gpx-rs/pkg": {
|
||||
"name": "gpx-rs",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"../gpx/node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"dev": true,
|
||||
@@ -5492,6 +5498,10 @@
|
||||
"resolved": "../gpx",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/gpx-rs": {
|
||||
"resolved": "../gpx-rs/pkg",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"dev": true,
|
||||
@@ -7716,6 +7726,16 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-wasm": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-wasm/-/vite-plugin-wasm-3.6.0.tgz",
|
||||
"integrity": "sha512-mL/QPziiIA4RAA6DkaZZzOstdwbW5jO4Vz7Zenj0wieKWBlNvIvX5L5ljum9lcUX0ShNfBgCNLKTjNkRVVqcsw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vite": "^2 || ^3 || ^4 || ^5 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vaul-svelte": "^1.0.0-next.7",
|
||||
"vite": "^6.3.5"
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-wasm": "^3.6.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
@@ -72,6 +73,7 @@
|
||||
"dexie": "^4.0.11",
|
||||
"file-saver": "^2.0.5",
|
||||
"gpx": "file:../gpx",
|
||||
"gpx-rs": "file:../gpx-rs/pkg",
|
||||
"immer": "^10.1.1",
|
||||
"jszip": "^3.10.1",
|
||||
"mapillary-js": "^4.1.2",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import { getURLForGoogleDriveFile } from '$lib/components/embedding/embedding';
|
||||
import { db } from '$lib/db';
|
||||
import { fileStateCollection } from '$lib/logic/file-state';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
const {
|
||||
treeFileView,
|
||||
@@ -36,6 +37,14 @@
|
||||
);
|
||||
|
||||
onMount(async () => {
|
||||
if (browser) {
|
||||
const wasm = await import('gpx-rs');
|
||||
const controller = new wasm.Controller();
|
||||
|
||||
console.log(controller);
|
||||
|
||||
controller.create_file();
|
||||
}
|
||||
settings.connectToDatabase(db);
|
||||
fileStateCollection.connectToDatabase(db).then(() => {
|
||||
let files: string[] = JSON.parse(page.url.searchParams.get('files') || '[]');
|
||||
|
||||
@@ -2,10 +2,11 @@ import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { enhancedImages } from '@sveltejs/enhanced-img';
|
||||
import { defineConfig } from 'vite';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import wasm from 'vite-plugin-wasm';
|
||||
|
||||
export default defineConfig({
|
||||
ssr: {
|
||||
noExternal: ['gpx'],
|
||||
},
|
||||
plugins: [enhancedImages(), tailwindcss(), sveltekit()],
|
||||
plugins: [enhancedImages(), tailwindcss(), wasm(), sveltekit()],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user