diff --git a/examples/mvtlayer.worker.js b/examples/mvtlayer.worker.js index 6de3774f1d..bc2ab5a20b 100644 --- a/examples/mvtlayer.worker.js +++ b/examples/mvtlayer.worker.js @@ -11,6 +11,20 @@ const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9 const worker = self; let frameState; +const canvas = new OffscreenCanvas(1, 1); + +function getCircularReplacer() { + const seen = new WeakSet(); + return function(key, value) { + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return '[circular]'; + } + seen.add(value); + } + return value; + }; +} function getTilePriority(tile, tileSourceKey, tileCenter, tileResolution) { return tilePriorityFunction(frameState, tile, tileSourceKey, tileCenter, tileResolution); @@ -24,13 +38,13 @@ const layer = new VectorTileLayer({ '{z}/{x}/{y}.vector.pbf?access_token=' + key }) }); +const renderer = layer.getRenderer(); const tileQueue = new TileQueue(getTilePriority, function() { - worker.postMessage({type: 'render'}); + worker.postMessage({type: 'request-render'}); }); const maxTotalLoading = 8; const maxNewLoads = 2; -const renderer = layer.getRenderer(); renderer.useContainer = function(target, transform, opacity) { target.style = {}; @@ -39,37 +53,38 @@ renderer.useContainer = function(target, transform, opacity) { this.container = { firstElementChild: target }; - worker.postMessage({ - type: 'transform-opacity', - transform: transform, - opacity: opacity + layer.once('postrender', function() { + const imageData = canvas.transferToImageBitmap(); + worker.postMessage({ + type: 'rendered', + imageData: imageData, + transform: transform, + opacity: opacity, + frameState: JSON.parse(JSON.stringify(frameState, getCircularReplacer())) + }, [imageData]); }); }; -let canvas; let rendering = false; worker.onmessage = function(event) { if (rendering) { // drop this frame + worker.postMessage({type: 'request-render'}); return; } - if (event.data.canvas) { - canvas = event.data.canvas; - } else { - frameState = event.data.frameState; - frameState.tileQueue = tileQueue; - frameState.viewState.projection.__proto__ = Projection.prototype; - rendering = true; - requestAnimationFrame(function() { - renderer.renderFrame(frameState, canvas); - if (tileQueue.getTilesLoading() < maxTotalLoading) { - tileQueue.reprioritize(); // FIXME only call if view has changed - tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); - } - rendering = false; - }); - } + frameState = event.data.frameState; + frameState.tileQueue = tileQueue; + frameState.viewState.projection.__proto__ = Projection.prototype; + rendering = true; + requestAnimationFrame(function() { + renderer.renderFrame(frameState, canvas); + if (tileQueue.getTilesLoading() < maxTotalLoading) { + tileQueue.reprioritize(); // FIXME only call if view has changed + tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); + } + rendering = false; + }); }; export let create; diff --git a/examples/offscreen-canvas-tiles.js b/examples/offscreen-canvas-tiles.js index af9f43e03f..0e619526aa 100644 --- a/examples/offscreen-canvas-tiles.js +++ b/examples/offscreen-canvas-tiles.js @@ -3,6 +3,8 @@ import View from '../src/ol/View.js'; import Layer from '../src/ol/layer/Layer.js'; //eslint-disable-next-line import Worker from 'worker-loader!./mvtlayer.worker.js'; +import {compose, create} from '../src/ol/transform.js'; +import {createTransformString} from '../src/ol/render/canvas.js'; const mvtLayerWorker = new Worker(); @@ -19,7 +21,28 @@ function getCircularReplacer() { }; } -let container, canvas; +let container, transformContainer, canvas, workerFrameState, mainThreadFrameState; + +function updateContainerTransform() { + if (workerFrameState) { + const viewState = mainThreadFrameState.viewState; + const renderedViewState = workerFrameState.viewState; + const center = viewState.center; + const resolution = viewState.resolution; + const rotation = viewState.rotation; + const renderedCenter = renderedViewState.center; + const renderedResolution = renderedViewState.resolution; + const renderedRotation = renderedViewState.rotation; + const transform = compose(create(), + (renderedCenter[0] - center[0]) / resolution, + (center[1] - renderedCenter[1]) / resolution, + renderedResolution / resolution, renderedResolution / resolution, + rotation - renderedRotation, + 0, 0); + transformContainer.style.transform = createTransformString(transform); + } + +} const map = new Map({ layers: [ @@ -30,16 +53,19 @@ const map = new Map({ container.style.position = 'absolute'; container.style.width = '100%'; container.style.height = '100%'; + transformContainer = document.createElement('div'); + transformContainer.style.position = 'absolute'; + transformContainer.style.width = '100%'; + transformContainer.style.height = '100%'; + container.appendChild(transformContainer); canvas = document.createElement('canvas'); canvas.style.position = 'absolute'; canvas.style.left = '0'; canvas.style.transformOrigin = 'top left'; - container.appendChild(canvas); - const offscreen = canvas.transferControlToOffscreen(); - mvtLayerWorker.postMessage({ - canvas: offscreen - }, [offscreen]); + transformContainer.appendChild(canvas); } + mainThreadFrameState = frameState; + updateContainerTransform(); mvtLayerWorker.postMessage({ frameState: JSON.parse(JSON.stringify(frameState, getCircularReplacer())) }); @@ -53,11 +79,18 @@ const map = new Map({ zoom: 2 }) }); -mvtLayerWorker.addEventListener('message', message => { - if (message.data.type === 'render') { +mvtLayerWorker.addEventListener('message', function(message) { + if (message.data.type === 'request-render') { map.render(); - } else if (canvas && message.data.type === 'transform-opacity') { - canvas.style.transform = message.data.transform; + } else if (canvas && message.data.type === 'rendered') { + transformContainer.style.transform = ''; + const imageData = message.data.imageData; + canvas.width = imageData.width; + canvas.height = imageData.height; + canvas.getContext('2d').drawImage(imageData, 0, 0); canvas.style.opacity = message.data.opacity; + canvas.style.transform = message.data.transform; + workerFrameState = message.data.frameState; + updateContainerTransform(); } });