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(