Use a web worker to calculate, to avoid locking up the browser. Also, use semicolons between points, and fix bug where it is impossible to calculate route when receiving points in the URL
This commit is contained in:
+29
-24
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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(';'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface StartSearchMessage {
|
||||
weights: number[][];
|
||||
}
|
||||
|
||||
export interface SearchStatusMessage {
|
||||
path: number[];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import Module, { type MainModule } from '../../native/salesman.js';
|
||||
import type { SearchStatusMessage, StartSearchMessage } from "./messages"
|
||||
|
||||
let modulePromise: Promise<MainModule> = 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);
|
||||
}
|
||||
Reference in New Issue
Block a user