Move buffer dissolve to worker

This commit is contained in:
2024-03-19 21:27:33 +01:00
parent 13d70e71cb
commit 3f529efe77
4 changed files with 50 additions and 39 deletions
+17 -2
View File
@@ -8,11 +8,14 @@ import {
tagsToHTML tagsToHTML
} from './overpass.ts'; } from './overpass.ts';
import { Circle, FeatureGroup, Polygon } from 'leaflet'; import { Circle, FeatureGroup, Polygon } from 'leaflet';
// @ts-ignore
import { buffer, truncate } from '@turf/turf';
export class ExclusionCircle extends FeatureGroup<Polygon | Circle> { export class ExclusionCircle extends FeatureGroup<Polygon | Circle> {
readonly id: string; readonly id: string;
readonly element: NWRElement; readonly element: NWRElement;
readonly reason: BannedArea; readonly reason: BannedArea;
readonly buffer: ReturnType<buffer> | null = null;
constructor(e: NWRElement) { constructor(e: NWRElement) {
super(); super();
@@ -36,7 +39,9 @@ export class ExclusionCircle extends FeatureGroup<Polygon | Circle> {
if (isWay(m)) { if (isWay(m)) {
m.geometry.length > 3 m.geometry.length > 3
? this.addLayer(this.getPolygon(m.geometry, color)) ? this.addLayer(this.getPolygon(m.geometry, color))
: this.addLayer(this.getCircle(m.geometry[0], color)); : m.geometry.forEach((g) =>
this.addLayer(this.getCircle(g, color))
);
} else if (isNode(m)) { } else if (isNode(m)) {
this.addLayer(this.getCircle(m, color)); this.addLayer(this.getCircle(m, color));
} }
@@ -47,7 +52,17 @@ export class ExclusionCircle extends FeatureGroup<Polygon | Circle> {
this.id = e.id; this.id = e.id;
this.element = e; this.element = e;
this.reason = reason; this.reason = reason;
try {
this.buffer = truncate(
buffer(this.toGeoJSON(), 100, { units: 'meters' })
);
} catch (err) {
console.error(
`Buffer calc for id=${e.id}, type=${e.type} failed`,
e,
err
);
}
this.bindPopup( this.bindPopup(
`<div class="whitespace-pre-wrap flex flex-col gap-3">${tagsToHTML({ reason, ...e.tags })}<a href="https://www.openstreetmap.org/${e.type}/${e.id}" target="_blank">↗ Auf OpenStreetMap öffnen</a></div>`, `<div class="whitespace-pre-wrap flex flex-col gap-3">${tagsToHTML({ reason, ...e.tags })}<a href="https://www.openstreetmap.org/${e.type}/${e.id}" target="_blank">↗ Auf OpenStreetMap öffnen</a></div>`,
{ maxWidth: 500 } { maxWidth: 500 }
View File
+20 -37
View File
@@ -6,21 +6,20 @@ import {
FeatureGroup, FeatureGroup,
GeoJSON, GeoJSON,
Map as LMap, Map as LMap,
Polygon,
Popup, Popup,
TileLayer TileLayer
} from 'leaflet'; } from 'leaflet';
import 'leaflet-easybutton'; import 'leaflet-easybutton';
import { BannedArea, BannedAreas, NWRElement } from './overpass.ts'; import { BannedArea, BannedAreas, NWRElement } from './overpass.ts';
import { colorMap, ExclusionCircle } from './ExclusionCircle.ts'; import { colorMap, ExclusionCircle } from './ExclusionCircle.ts';
import { // @ts-ignore
buffer, import { FeatureCollection, truncate } from '@turf/turf';
dissolve,
featureCollection,
FeatureCollection,
truncate
} from '@turf/turf';
// @ts-ignore // @ts-ignore
import type { Feature } from '@turf/helpers'; import type { Feature } from '@turf/helpers';
import workerUrl from './worker/worker.ts?worker&url';
const worker = new Worker(workerUrl, { type: 'module' });
const m_mono = new TileLayer( const m_mono = new TileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
@@ -70,8 +69,18 @@ map.on('moveend', async () => {
}); });
let loading = false; let loading = false;
worker.addEventListener(
'message',
(b: MessageEvent<FeatureCollection<Polygon>>) => {
exclusionZone.clearLayers();
const zone = new GeoJSON(b.data, {
style: { color: 'red', fillOpacity: 0.1, weight: 1 }
});
exclusionZone.addLayer(zone);
exclusionZone.bringToBack();
}
);
function showBuffer() { function showBuffer() {
console.time('prepare');
map.attributionControl.setPrefix('Berechne Zone'); map.attributionControl.setPrefix('Berechne Zone');
const fs = Object.entries(buffers) const fs = Object.entries(buffers)
.filter(([k]) => map.hasLayer(features[k as keyof typeof features])) .filter(([k]) => map.hasLayer(features[k as keyof typeof features]))
@@ -83,22 +92,7 @@ function showBuffer() {
}); });
if (fs.length > 0) { if (fs.length > 0) {
exclusionZone.clearLayers(); worker.postMessage(fs);
console.timeEnd('prepare');
try {
console.time('dissolve');
const b = dissolve(featureCollection(fs));
const zone = new GeoJSON(b, {
style: { color: 'red', fillOpacity: 0.1, weight: 1 }
});
console.timeEnd('dissolve');
console.time('render');
exclusionZone.addLayer(zone);
console.timeEnd('render');
exclusionZone.bringToBack();
} catch (err) {
console.error('dissolve', err);
}
} }
map.attributionControl.setPrefix(''); map.attributionControl.setPrefix('');
} }
@@ -145,7 +139,6 @@ out geom;`;
.then((r) => r.elements as NWRElement[]); .then((r) => r.elements as NWRElement[]);
loading = false; loading = false;
console.time('parse');
map.attributionControl.setPrefix('Berechne Orte...'); map.attributionControl.setPrefix('Berechne Orte...');
const ids = elements.map((e) => e.id); const ids = elements.map((e) => e.id);
const exclude: ExclusionCircle[] = []; const exclude: ExclusionCircle[] = [];
@@ -168,20 +161,10 @@ out geom;`;
} }
features[marker.reason].addLayer(marker); features[marker.reason].addLayer(marker);
try { if (marker.buffer) {
const b = buffer(marker.toGeoJSON(), 100, { units: 'meters' }); buffers[marker.reason].push(marker.buffer);
// new GeoJSON(b).addTo(map);
buffers[marker.reason].push(truncate(b));
} catch (err) {
console.error(
`Buffer calc for id=${e.id}, type=${e.type} failed`,
e,
err
);
} }
}); });
console.timeEnd('parse');
queueMicrotask(showBuffer); queueMicrotask(showBuffer);
map.attributionControl.setPrefix(''); map.attributionControl.setPrefix('');
+13
View File
@@ -0,0 +1,13 @@
// @ts-ignore
import { Feature } from '@turf/helpers';
// @ts-ignore
import { dissolve, featureCollection } from '@turf/turf';
self.onmessage = function (e: MessageEvent<Feature[]>) {
try {
const b = dissolve(featureCollection(e.data));
self.postMessage(b);
} catch (err) {
console.error('dissolve', err);
}
};