-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathpredictions-worker.ts
More file actions
127 lines (117 loc) · 3.59 KB
/
Copy pathpredictions-worker.ts
File metadata and controls
127 lines (117 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import Map from 'ol/Map'
import View from 'ol/View'
import VectorTileLayer from 'ol/layer/VectorTile'
import { PMTilesVectorSource } from 'ol-pmtiles'
import { Fill, Stroke, Style } from 'ol/style'
import { createXYZ } from 'ol/tilegrid'
import { confidenceColorScale, getColorForValue } from '../layers/color-scales'
const TILE_SIZE = 512
const tileGrid = createXYZ({ tileSize: [TILE_SIZE, TILE_SIZE] })
const canvas = new OffscreenCanvas(TILE_SIZE, TILE_SIZE)
let currentThreshold = 0.4
const key = 'confidence_mean'
const stroke = new Stroke({
color: '',
width: 1,
lineCap: 'butt',
lineJoin: 'miter',
miterLimit: 1,
})
const fill = new Fill({ color: '' })
const polyStyle = new Style({ stroke, fill })
const smallStyle = new Style({ stroke })
const layer = new VectorTileLayer({
renderMode: 'vector',
declutter: false,
})
layer.setStyle((feature, resolution) => {
const confidence = feature.get(key)
if (confidence <= currentThreshold) return undefined
stroke.setColor(getColorForValue(confidenceColorScale, confidence, 1))
const extent = feature.getGeometry()!.getExtent()
const widthPx = (extent[2] - extent[0]) / resolution
const heightPx = (extent[3] - extent[1]) / resolution
if (widthPx < 3 && heightPx < 3) return smallStyle
fill.setColor(getColorForValue(confidenceColorScale, confidence, 0.35))
return polyStyle
})
const map = new Map({
target: canvas,
layers: [layer],
pixelRatio: 1,
controls: [],
interactions: [],
})
map.setSize([TILE_SIZE, TILE_SIZE])
// Workaround for OpenLayers not clearing the canvas between renders
//FIXME: Remove when https://github.com/openlayers/openlayers/pull/17453 is released
layer.on('prerender', () => {
canvas.width = TILE_SIZE
})
let sourceReady: Promise<void> | null = null
let isRendering = false
let pendingRender: { tile: number[] } | null = null
function startRender(tile: number[]) {
isRendering = true
const view = new View({
center: tileGrid.getTileCoordCenter(tile),
resolution: tileGrid.getResolution(tile[0]),
})
map.setView(view)
map.once('rendercomplete', () => {
if (pendingRender) {
const { tile: nextTile } = pendingRender
pendingRender = null
startRender(nextTile)
return
}
isRendering = false
const imageData = canvas.transferToImageBitmap()
self.postMessage({ action: 'rendered', imageData }, [imageData] as any)
})
}
self.addEventListener('message', async ({ data: { action, tile, url, threshold } }) => {
if (action === 'init') {
currentThreshold = threshold
const source = new PMTilesVectorSource({ overlaps: false, url })
layer.setSource(source)
sourceReady = new Promise<void>((resolve, reject) => {
if (source.getState() === 'ready') {
resolve()
return
}
if (source.getState() === 'error') {
reject(new Error('Source failed to load'))
return
}
const timeout = setTimeout(() => reject(new Error('Source timed out')), 10000)
const check = () => {
if (source.getState() === 'ready') {
clearTimeout(timeout)
resolve()
} else if (source.getState() === 'error') {
clearTimeout(timeout)
reject(new Error('Source failed to load'))
} else source.once('change', check)
}
source.once('change', check)
})
return
}
if (action === 'updateThreshold') {
currentThreshold = threshold
return
}
if (action !== 'render') return
try {
await sourceReady
} catch {
self.postMessage({ action: 'error' })
return
}
if (isRendering) {
pendingRender = { tile }
} else {
startRender(tile)
}
})