feat(directions): run route computation in a Web Worker with live progress (off UI thread)
This commit is contained in:
parent
62ddbf160c
commit
591fafc5de
@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import type { Map as LeafletMap } from 'leaflet';
|
||||
import { search, type Searchable, type SearchResult } from '$lib/search';
|
||||
import { geocode, type GeocodedPlace } from '$lib/geocode';
|
||||
import DirectionsPanel from '$lib/components/DirectionsPanel.svelte';
|
||||
import { prefs } from '$lib/prefs';
|
||||
import { route, type RouteGraph, type AvoidRule, type RouteResult } from '$lib/routing';
|
||||
import type { RouteGraph, AvoidRule, RouteResult } from '$lib/routing';
|
||||
|
||||
type FeatureCollection = {
|
||||
type: string;
|
||||
@ -71,6 +71,11 @@
|
||||
let routeLoading = $state(false);
|
||||
let routeProgress = $state(0);
|
||||
let graphLabel = $derived(dumpLayers[0]?.label ?? '');
|
||||
// --- Web Worker for route computation (off the UI thread) ---
|
||||
let routeWorker: Worker | null = null;
|
||||
let routeToken = 0;
|
||||
let pendingResolve: ((r: RouteResult) => void) | null = null;
|
||||
let pendingReject: ((e: Error) => void) | null = null;
|
||||
// --- search state ---
|
||||
const searchables: Searchable[] = [];
|
||||
let query = $state('');
|
||||
@ -177,24 +182,63 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Run a route. Task 4 replaces this with a Web Worker call; for now a
|
||||
// synchronous in-thread computation keeps the panel functional.
|
||||
// Lazily create the routing worker. It is recreated on demand and kept for
|
||||
// the component lifetime (destroyed on unmount).
|
||||
function ensureWorker(): Worker {
|
||||
if (routeWorker) return routeWorker;
|
||||
const w = new Worker(new URL('../routing.worker.ts', import.meta.url), { type: 'module' });
|
||||
w.onmessage = (e: MessageEvent) => {
|
||||
const msg = e.data as { type: string; pct?: number; result?: RouteResult; error?: string; message?: string; token?: number };
|
||||
if (msg.type === 'progress' && msg.pct !== undefined) {
|
||||
routeProgress = msg.pct;
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'done' && pendingResolve) {
|
||||
const r = pendingResolve; pendingResolve = null; pendingReject = null;
|
||||
computingRoute = false;
|
||||
r(msg.result as RouteResult);
|
||||
} else if (msg.type === 'error' && pendingReject) {
|
||||
const rj = pendingReject; pendingResolve = null; pendingReject = null;
|
||||
computingRoute = false;
|
||||
rj(new Error((msg as { message?: string }).message ?? 'Route computation failed.'));
|
||||
}
|
||||
};
|
||||
routeWorker = w;
|
||||
return w;
|
||||
}
|
||||
function destroyWorker() {
|
||||
if (routeWorker) { routeWorker.terminate(); routeWorker = null; }
|
||||
}
|
||||
|
||||
// Run a route in the Web Worker, reporting progress back to the panel.
|
||||
async function runRoute(
|
||||
from: [number, number],
|
||||
to: [number, number],
|
||||
avoid: AvoidRule[]
|
||||
): Promise<RouteResult> {
|
||||
try {
|
||||
if (!routeGraph) await loadRouteGraph();
|
||||
if (!routeGraph) throw new Error('Road data layer is not available.');
|
||||
computingRoute = true;
|
||||
routeProgress = 1; // sync: no live progress in fallback
|
||||
return route(routeGraph, from, to, routePois, avoid);
|
||||
} finally {
|
||||
computingRoute = false;
|
||||
}
|
||||
if (!routeGraph) await loadRouteGraph();
|
||||
if (!routeGraph) throw new Error('Road data layer is not available.');
|
||||
const w = ensureWorker();
|
||||
computingRoute = true;
|
||||
routeProgress = 0;
|
||||
const token = ++routeToken;
|
||||
return await new Promise<RouteResult>((resolve, reject) => {
|
||||
pendingResolve = resolve;
|
||||
pendingReject = reject;
|
||||
w.postMessage({
|
||||
type: 'route',
|
||||
token,
|
||||
graph: routeGraph,
|
||||
pois: routePois,
|
||||
from,
|
||||
to,
|
||||
avoid
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy(destroyWorker);
|
||||
|
||||
function toggle(name: string) {
|
||||
const g = layerGroups[name];
|
||||
if (!g) return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user