diff --git a/src/main.ts b/src/main.ts index cdc4a86..07c40db 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,4 @@ import MapHandler from './map/maphandler'; -import Module, { type MainModule } from '../native/salesman.js'; import haversine from 'haversine-distance'; import './style.css'; import { LatLng } from 'leaflet'; @@ -8,12 +7,11 @@ import { createUrl, parseUrl } from './url/UrlHandler.js'; import { wktToGeoJSON } from '@terraformer/wkt'; import PPENHandler from './files/ppenhandler.js'; import type { GeoJsonObject } from 'geojson'; +import type { SearchStatusMessage, StartSearchMessage } from './worker/messages.js'; // Outside influences let mapHandler = new MapHandler(); -let module: MainModule = await Module(); - - +let worker = new Worker(new URL('./worker/worker.ts', import.meta.url), {type: 'module'}); // HTTP elements to be edited let clearMapButton = document.getElementById('clear-map'); @@ -57,7 +55,7 @@ mapHandler.addMarkerClickedListener((latLng) => { awaiting(latLng); }); awaitingResolutions = []; -}) +}); @@ -65,6 +63,7 @@ mapHandler.addMarkerClickedListener((latLng) => { interface State { points: LatLng[] | null, distances: [LatLng, LatLng, number][], + calculating: boolean, foundPath: number[] | null, complexPath: GeoJsonObject | null, @@ -81,7 +80,8 @@ interface State { let state: State = { points: null, distances: [], - foundPath: [], + calculating: false, + foundPath: null, complexPath: null, ppenHandler: null, @@ -122,7 +122,8 @@ function updateState() { // Always just allow the share link button, do nothing here // Only allow the calculate route button when we have more than three points, and don't already have a route - if (state.points == null || state.points.length < 3 || state.foundPath != null) { + // Also, disallow the get route button when currently calculating + if (state.points == null || state.points.length < 3 || state.foundPath != null || state.calculating) { allowCalculateRoute = false; } @@ -283,16 +284,24 @@ function updateState() { } } -function calculateRoute(): number[] { +// In case of messages from the web worker, do work +worker.onmessage = e => { + let message = e.data as SearchStatusMessage; + state.foundPath = message.path; + state.calculating = false; + updateState(); +} + +function calculateRoute(): void { if (!state.points) { - return []; + return; } let points: LatLng[] = state.points; - let weights = new module.Weights(); + let weights: number[][] = []; for (var i = 0; i < points.length; i++) { - let weightsRow = new module.WeightsRow(); + let weightsRow: number[] = []; for (var j = 0; j < points.length; j++) { var distance: number; if (i == j) { @@ -312,20 +321,16 @@ function calculateRoute(): number[] { } } - weightsRow.push_back(distance); + weightsRow.push(distance); } - weights.push_back(weightsRow); + weights.push(weightsRow); } - let path = module.findShortestPath(weights); - var foundPath = []; - for (var i = 0; i < path.size(); i++) { - let pointIndex = path.get(i); - if (typeof pointIndex != 'undefined') { - foundPath.push(pointIndex); - } - } - return foundPath; + let startSearchMessage: StartSearchMessage = { + weights: weights + }; + + worker.postMessage(startSearchMessage); } function populateDistancesTable() { @@ -788,9 +793,9 @@ shareLinkButton?.addEventListener('click', async _ => { calculateRouteButton?.addEventListener('click', _ => { if (calculateRouteButton.classList.contains('clickable')) { - let path = calculateRoute(); - state.foundPath = path; + state.calculating = true; updateState(); + calculateRoute(); } }); diff --git a/src/url/UrlHandler.ts b/src/url/UrlHandler.ts index 1775bee..fc71a12 100644 --- a/src/url/UrlHandler.ts +++ b/src/url/UrlHandler.ts @@ -11,7 +11,7 @@ export function parseUrl(url: string): [LatLng[] | null, [LatLng, LatLng, number points = []; let pointsString = parsedUrl.searchParams.get('points'); - pointsString?.split('-').forEach(pointString => { + pointsString?.split(';').forEach(pointString => { let splitString = pointString.split(','); if (splitString && splitString.length == 2) { let lat = parseFloat(splitString[0]); @@ -32,7 +32,7 @@ export function parseUrl(url: string): [LatLng[] | null, [LatLng, LatLng, number distances = []; let distancesString = parsedUrl.searchParams.get('distances'); - distancesString?.split('-').forEach(distanceString => { + distancesString?.split(';').forEach(distanceString => { let splitString = distanceString.split(','); if (splitString && splitString.length == 3) { let from = parseInt(splitString[0]); @@ -67,7 +67,7 @@ export function createUrl(clickedPoints: LatLng[] | null, definedDistances: [Lat if(clickedPoints) { let pointStrings = clickedPoints.map(latLng => latLng.lat.toFixed(6) + ',' + latLng.lng.toFixed(6)); if (pointStrings.length > 0) { - urlStrings.push('points=' + pointStrings.join('-')); + urlStrings.push('points=' + pointStrings.join(';')); } } @@ -90,7 +90,7 @@ export function createUrl(clickedPoints: LatLng[] | null, definedDistances: [Lat } if (distancesStrings.length > 0) { - urlStrings.push('distances=' + distancesStrings.join('-')); + urlStrings.push('distances=' + distancesStrings.join(';')); } } diff --git a/src/worker/messages.ts b/src/worker/messages.ts new file mode 100644 index 0000000..848aa3b --- /dev/null +++ b/src/worker/messages.ts @@ -0,0 +1,7 @@ +export interface StartSearchMessage { + weights: number[][]; +} + +export interface SearchStatusMessage { + path: number[]; +} \ No newline at end of file diff --git a/src/worker/worker.ts b/src/worker/worker.ts new file mode 100644 index 0000000..d2aa629 --- /dev/null +++ b/src/worker/worker.ts @@ -0,0 +1,32 @@ +import Module, { type MainModule } from '../../native/salesman.js'; +import type { SearchStatusMessage, StartSearchMessage } from "./messages" + +let modulePromise: Promise = Module(); + +onmessage = async (e) => { + let module = await modulePromise; + let message = e.data as StartSearchMessage; + let nativeWeights = new module.Weights; + message.weights.forEach(weightsRow => { + let nativeWeightsRow = new module.WeightsRow(); + weightsRow.forEach(weight => { + nativeWeightsRow.push_back(weight); + }); + nativeWeights.push_back(nativeWeightsRow); + }); + + let path = module.findShortestPath(nativeWeights); + + let foundPath = []; + for (var i = 0; i < path.size(); i++) { + let pointIndex = path.get(i); + if (typeof pointIndex != 'undefined') { + foundPath.push(pointIndex); + } + }; + + let finishedMessage: SearchStatusMessage = { + path: foundPath + }; + postMessage(finishedMessage); +} \ No newline at end of file