diff --git a/examples/offscreen-canvas.css b/examples/offscreen-canvas.css index aa8012667b..c062d5dcb5 100644 --- a/examples/offscreen-canvas.css +++ b/examples/offscreen-canvas.css @@ -1,5 +1,6 @@ .map { background: rgba(232, 230, 223, 1); + position: relative; } .map .ol-rotate { left: .5em; @@ -7,3 +8,16 @@ top: auto; right: auto; } + +.info { + z-index: 1; + opacity: 0; + position: absolute; + bottom: 0; + left: 0; + margin: 0; + background: rgba(0,60,136,0.7); + color: white; + border: 0; + transition: opacity 100ms ease-in; +} diff --git a/examples/offscreen-canvas.html b/examples/offscreen-canvas.html index 192af39c4f..65438c4519 100644 --- a/examples/offscreen-canvas.html +++ b/examples/offscreen-canvas.html @@ -11,4 +11,6 @@ cloak: value: Get your own API key at https://www.maptiler.com/cloud/ --- -
+
+
+
\ No newline at end of file diff --git a/examples/offscreen-canvas.js b/examples/offscreen-canvas.js index c70de0afcb..3e5f62eea6 100644 --- a/examples/offscreen-canvas.js +++ b/examples/offscreen-canvas.js @@ -99,6 +99,17 @@ const map = new Map({ }); map.addControl(new FullScreen()); +map.on('pointermove', function (evt) { + if (evt.dragging) { + return; + } + const pixel = map.getEventPixel(evt.originalEvent); + worker.postMessage({ + action: 'requestFeatures', + pixel: pixel, + }); +}); + // Worker messaging and actions worker.addEventListener('message', (message) => { if (message.data.action === 'loadImage') { @@ -119,7 +130,9 @@ worker.addEventListener('message', (message) => { } ); }); - image.src = event.data.src; + image.src = message.data.src; + } else if (message.data.action === 'getFeatures') { + showInfo(message.data.features); } else if (message.data.action === 'requestRender') { // Worker requested a new render frame map.render(); @@ -137,3 +150,19 @@ worker.addEventListener('message', (message) => { rendering = false; } }); + +const info = document.getElementById('info'); +function showInfo(propertiesFromFeatures) { + if (propertiesFromFeatures.length == 0) { + info.innerText = ''; + info.style.opacity = 0; + return; + } + const properties = propertiesFromFeatures.map((e) => + Object.keys(e) + .filter((key) => !key.includes(':')) + .reduce((newObj, currKey) => ((newObj[currKey] = e[currKey]), newObj), {}) + ); + info.innerText = JSON.stringify(properties, null, 2); + info.style.opacity = 1; +} diff --git a/examples/offscreen-canvas.worker.js b/examples/offscreen-canvas.worker.js index cc0cba9f47..df08d464e5 100644 --- a/examples/offscreen-canvas.worker.js +++ b/examples/offscreen-canvas.worker.js @@ -111,7 +111,6 @@ function loadStyles() { } // Minimal map-like functionality for rendering - const tileQueue = new TileQueue( (tile, tileSourceKey, tileCenter, tileResolution) => tilePriorityFunction( @@ -128,6 +127,23 @@ const maxTotalLoading = 8; const maxNewLoads = 2; worker.addEventListener('message', (event) => { + if (event.data.action === 'requestFeatures') { + const layersInView = layers.filter((l) => + inView(l.getLayerState(), frameState.viewState) + ); + const observables = layersInView.map((l) => + l.getFeatures(event.data.pixel) + ); + Promise.all(observables).then((res) => { + const features = res.flat(); + worker.postMessage({ + action: 'getFeatures', + features: JSON.parse(stringify(features.map((e) => e.getProperties()))), + }); + }); + return; + } + if (event.data.action !== 'render') { return; } diff --git a/src/ol/dom.js b/src/ol/dom.js index 3b251301a7..b212a1361d 100644 --- a/src/ol/dom.js +++ b/src/ol/dom.js @@ -10,9 +10,15 @@ import {WORKER_OFFSCREEN_CANVAS} from './has.js'; * @param {number} [opt_width] Canvas width. * @param {number} [opt_height] Canvas height. * @param {Array} [opt_canvasPool] Canvas pool to take existing canvas from. + * @param {CanvasRenderingContext2DSettings} [opt_Context2DSettings] CanvasRenderingContext2DSettings * @return {CanvasRenderingContext2D} The context. */ -export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) { +export function createCanvasContext2D( + opt_width, + opt_height, + opt_canvasPool, + opt_Context2DSettings +) { const canvas = opt_canvasPool && opt_canvasPool.length ? opt_canvasPool.shift() @@ -26,7 +32,10 @@ export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) { canvas.height = opt_height; } //FIXME Allow OffscreenCanvasRenderingContext2D as return type - return /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')); + return /** @type {CanvasRenderingContext2D} */ (canvas.getContext( + '2d', + opt_Context2DSettings + )); } /** diff --git a/src/ol/render/canvas/hitdetect.js b/src/ol/render/canvas/hitdetect.js index d32acc468c..28ae0ea733 100644 --- a/src/ol/render/canvas/hitdetect.js +++ b/src/ol/render/canvas/hitdetect.js @@ -91,10 +91,13 @@ export function createHitDetectionImageData( continue; } - const img = document.createElement('canvas'); - img.width = imgSize[0]; - img.height = imgSize[1]; - const imgContext = img.getContext('2d', {alpha: false}); + const imgContext = createCanvasContext2D( + imgSize[0], + imgSize[1], + undefined, + {alpha: false} + ); + const img = imgContext.canvas; imgContext.fillStyle = color; imgContext.fillRect(0, 0, img.width, img.height); style.setImage(