import Layer from '../src/ol/layer/Layer.js'; import Map from '../src/ol/Map.js'; import Source from '../src/ol/source/Source.js'; import View from '../src/ol/View.js'; import Worker from 'worker-loader!./offscreen-canvas.worker.js'; //eslint-disable-line import stringify from 'json-stringify-safe'; import {FullScreen} from '../src/ol/control.js'; import {compose, create} from '../src/ol/transform.js'; import {createTransformString} from '../src/ol/render/canvas.js'; import {createXYZ} from '../src/ol/tilegrid.js'; const worker = new Worker(); let container, transformContainer, canvas, rendering, workerFrameState, mainThreadFrameState; // Transform the container to account for the differnece between the (newer) // main thread frameState and the (older) worker frameState 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 = create(); // Skip the extra transform for rotated views, because it will not work // correctly in that case if (!rotation) { compose( transform, (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: [ new Layer({ render: function (frameState) { if (!container) { container = document.createElement('div'); 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'; transformContainer.appendChild(canvas); } mainThreadFrameState = frameState; updateContainerTransform(); if (!rendering) { rendering = true; worker.postMessage({ action: 'render', frameState: JSON.parse(stringify(frameState)), }); } else { frameState.animate = true; } return container; }, source: new Source({ attributions: [ '© MapTiler', '© OpenStreetMap contributors', ], }), }), ], target: 'map', view: new View({ resolutions: createXYZ({tileSize: 512}).getResolutions89, center: [0, 0], zoom: 2, }), }); map.addControl(new FullScreen()); // Worker messaging and actions worker.addEventListener('message', (message) => { if (message.data.action === 'loadImage') { // Image loader for ol-mapbox-style const image = new Image(); image.crossOrigin = 'anonymous'; image.addEventListener('load', function () { createImageBitmap(image, 0, 0, image.width, image.height).then( (imageBitmap) => { worker.postMessage( { action: 'imageLoaded', image: imageBitmap, src: message.data.src, }, [imageBitmap] ); } ); }); image.src = event.data.src; } else if (message.data.action === 'requestRender') { // Worker requested a new render frame map.render(); } else if (canvas && message.data.action === 'rendered') { // Worker provies a new render frame requestAnimationFrame(function () { const imageData = message.data.imageData; canvas.width = imageData.width; canvas.height = imageData.height; canvas.getContext('2d').drawImage(imageData, 0, 0); canvas.style.transform = message.data.transform; workerFrameState = message.data.frameState; updateContainerTransform(); }); rendering = false; } });