Migration to new Rust-based engine (#401)

* wasm first steps

* parsing start

* parsing continued

* progress

* progress

* progress

* progress

* progress

* progress

* progress

* progress

* fixes

* reorganize

* change type

* fix

* progress

* refactoring

* progress

* progress

* progress

* keep style info

* progress

* progress

* remove (copy) in name

* progress

* merge methods into 1

* splice

* progress

* progress

* progress

* cleaning

* progress

* progress

* progress

* visibility

* progress

* progress

* progress

* progress

* progress

* fixes

* progress

* fix markers

* fix

* progress

* progress

* progress

* progress

* progress

* progress

* small fix

* use engine info

* fix popups

* small fix

* progress

* progress

* progress

* clean tool

* handle self closing elements

* reduce data exchanges across boundary

* copy on wasm side to avoid any data corruption

* speed fix

* routing

* refactoring

* reverse

* reverse

* crop

* split

* merge

* progress

* time tool

* fix bounds for waypoints

* reduce

* fix reactivity

* handle corrupt time data

* export

* progress

* remove gpx js package

* remove todo

* update readme

* cleaning

* progress

* fix link fields

* remove unused fields

* refactoring and tests

* import and export of routes, ref #192

* per-chunk categories storage

* cross-tab sync

* outdated state

* refactoring

* reorder methods

* refactoring

* fix

* improve flow

* renaming

* progress

* progress

* fix

* progress

* per file history

* keep original flag

* use history variant

* fix

* progress

* file explorer

* progress

* fix

* sticky folders

* improved sticky folders

* fix sortable

* fix sortable

* fix

* fix tab size

* no file delete on desktop

* fix routing on other file

* fix sorting

* remember language

* open links in browser

* commit missing changes

* avoid selecting on resize

* clarify filename

* explorer actions

* fix folder styling

* drop anywhere in folder

* cleaning

* fixes

* remove focus-ring

* full screen

* small fix

* consistent highlight color

* improved preview

* performance improvements

* sparser data transfers

* sparser data transfers

* show popup once data is loaded

* fix routing control size

* fix

* sparse desktop build

* remove custom ign styles

* use new endpoint for openhikingmap

* strip native menu

* reorder context menu items

* route full support

* route - track conversion

* create route file action

* route export, filter out anchors at high zoom level

* clarify name handling

* move hide & center to view

* routes continued

* update docs

* fix power format, closes #378

* lint fixes

* fix display of additional data with gaps, closes #361

* fix linting issues

* fix import modules

* fix multidrag

* change base to resolve

* fix type errors

* fix layer typings

* fix last type error

* each keys

* improve typings

* deploy to cloudflare

---------

Co-authored-by: vcoppe <vcoppe@hexaly.com>
This commit is contained in:
vcoppeandvcoppe authored and GitHub committed 2026-10-31 18:08:22 +01:00
1 parent 6a0d434371
commit 8fe7d8d64d
484 files changed
+53949 -41152

No files matched your search

@@ -0,0 +1,95 @@
/**
* Computes the statistics of `data/example/example.gpx` with the engine, and writes them to
* `data/example/example-data.ts`, where the pages that show an example (the home page, the
* documentation) take them from. Run it when the example, or the way the engine computes the
* statistics, changes:
*
* npm run generate:example
*
* The engine has to be built (`wasm-pack build --target bundler`, in
* `wasm`).
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import prettier from 'prettier';
const here = path.dirname(fileURLToPath(import.meta.url));
const example = path.resolve(here, '../data/example');
const packageDirectory = path.resolve(here, '../../../../wasm/pkg');
export const exampleGPX = path.join(example, 'example.gpx');
export const exampleData = path.join(example, 'example-data.ts');
/** Whether the engine is built. */
export function engineIsBuilt() {
return fs.existsSync(path.join(packageDirectory, 'gpx_wasm_bg.wasm'));
}
/** Loads the engine in Node: the package is made for bundlers, which import the wasm file. */
async function loadEngine() {
const glue = await import(pathToFileURL(path.join(packageDirectory, 'gpx_wasm_bg.js')).href);
const { instance } = await WebAssembly.instantiate(
fs.readFileSync(path.join(packageDirectory, 'gpx_wasm_bg.wasm')),
{ './gpx_wasm_bg.js': glue }
);
glue.__wbg_set_wasm(instance.exports);
(instance.exports.__wbindgen_start as () => void)();
return glue as typeof import('gpx-wasm');
}
type Values = Float64Array | BigInt64Array | undefined;
/** The arrays that the engine has for the example, which are all the pages need. */
export async function computeExampleData() {
const engine = await loadEngine();
engine.start();
const data = fs.readFileSync(exampleGPX);
engine.load_files(new Uint8Array(data), Uint32Array.from([data.length]), ['example']);
// numbers are enough for the times, which are milliseconds
const numbers = (values: Values | Uint32Array) =>
values && Array.from(values as ArrayLike<number | bigint>, (value) => Number(value));
const length = engine.total_distance().length;
const points = Array.from({ length }, (_, index) => engine.selection_point(index)!);
const slopeSegmentStarts = Array.from(engine.slope_segment_starts());
return {
global: engine.selection_statistics(),
totalDistance: numbers(engine.total_distance()),
movingDistance: numbers(engine.moving_distance()),
totalTime: numbers(engine.total_time()),
movingTime: numbers(engine.moving_time()),
elevationGain: numbers(engine.elevation_gain()),
elevationLoss: numbers(engine.elevation_loss()),
slope: points.map((point) => point.slope!),
slopeSegmentStarts,
slopeSegmentSlopes: numbers(engine.slope_segment_slopes()),
// the length of each segment, which is the one of its trackpoints
slopeSegmentDistances: slopeSegmentStarts.map(
(start) => points[start].slopeSegmentDistance!
),
lng: numbers(engine.lng()),
lat: numbers(engine.lat()),
ele: numbers(engine.ele()),
timestamps: points.map((point) => point.time!),
speed: numbers(engine.speed()),
atemp: numbers(engine.atemp()),
};
}
async function generate() {
const data = await computeExampleData();
const source = `// Generated by src/lib/scripts/example-statistics.ts from example.gpx: do not edit.
export const exampleData = ${JSON.stringify(data)};
`;
const options = (await prettier.resolveConfig(exampleData)) ?? {};
fs.writeFileSync(
exampleData,
await prettier.format(source, { ...options, parser: 'typescript' })
);
console.log(`Wrote ${path.relative(process.cwd(), exampleData)}`);
}
if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) {
generate();
}
+2 -2
View File
@@ -1,7 +1,7 @@
import fs from 'fs';
import { languages } from '../languages';
import { languages } from '$lib/i18n/languages';
function localizeManifest(manifestTemplateData: any, language: string) {
function localizeManifest(manifestTemplateData: Record<string, unknown>, language: string) {
const localizedManifestFile = `static/${language}.manifest.webmanifest`;
const localizedStringsFile = `src/locales/${language}.json`;
const localizedStrings = JSON.parse(fs.readFileSync(localizedStringsFile, 'utf8'));
+1 -1
View File
@@ -1,6 +1,6 @@
import fs from 'fs';
import { glob } from 'glob';
import { languages } from '$lib/languages';
import { languages } from '$lib/i18n/languages';
function getURLForLanguage(lang: string, path: string): string {
return `https://gpx.studio${lang === 'en' ? '' : `/${lang}`}${path}`;