diff --git a/examples/mvtlayer.worker.js b/examples/mvtlayer.worker.js deleted file mode 100644 index 16a555e052..0000000000 --- a/examples/mvtlayer.worker.js +++ /dev/null @@ -1,98 +0,0 @@ -import VectorTileLayer from '../src/ol/layer/VectorTile.js'; -import VectorTileSource from '../src/ol/source/VectorTile.js'; -import MVT from '../src/ol/format/MVT.js'; -import {Projection} from '../src/ol/proj.js'; -import TileQueue from '../src/ol/TileQueue.js'; -import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js'; -import {Style, Fill, Stroke, Icon, Text} from '../src/ol/style.js'; -import createMapboxStreetsV6Style from './resources/mapbox-streets-v6-style.js'; -import {renderDeclutterItems} from '../src/ol/render.js'; - -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; - -/** @type {any} */ -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); -} - -const layer = new VectorTileLayer({ - declutter: true, - style: createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text), - source: new VectorTileSource({ - format: new MVT(), - url: 'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + - '{z}/{x}/{y}.vector.pbf?access_token=' + key - }) -}); -const renderer = layer.getRenderer(); -const tileQueue = new TileQueue(getTilePriority, function() { - worker.postMessage({action: 'request-render'}); -}); -const maxTotalLoading = 8; -const maxNewLoads = 2; - -let rendererTransform, rendererOpacity; -renderer.useContainer = function(target, transform, opacity) { - target.style = {}; - this.canvas = target; - this.context = target.getContext('2d'); - this.container = { - firstElementChild: target - }; - rendererTransform = transform; - rendererOpacity = opacity; -}; - -let rendering = false; - -worker.addEventListener('message', function(event) { - if (event.data.action !== 'render') { - return; - } - if (rendering) { - // drop this frame - worker.postMessage({action: 'request-render'}); - return; - } - frameState = event.data.frameState; - frameState.tileQueue = tileQueue; - frameState.viewState.projection.__proto__ = Projection.prototype; - rendering = true; - requestAnimationFrame(function() { - renderer.renderFrame(frameState, canvas); - renderDeclutterItems(frameState, null); - if (tileQueue.getTilesLoading() < maxTotalLoading) { - tileQueue.reprioritize(); // FIXME only call if view has changed - tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); - } - const imageData = canvas.transferToImageBitmap(); - worker.postMessage({ - action: 'rendered', - imageData: imageData, - transform: rendererTransform, - opacity: rendererOpacity, - frameState: JSON.parse(JSON.stringify(frameState, getCircularReplacer())) - }, [imageData]); - rendering = false; - }); -}); - -export let create; diff --git a/examples/offscreen-canvas-tiles.css b/examples/offscreen-canvas-tiles.css index 33e90f7301..9fde055492 100644 --- a/examples/offscreen-canvas-tiles.css +++ b/examples/offscreen-canvas-tiles.css @@ -1,3 +1,3 @@ .map { - background: #f8f4f0; + background: rgba(232, 230, 223, 1); } diff --git a/examples/offscreen-canvas-tiles.js b/examples/offscreen-canvas-tiles.js index 60ee70480c..29243c2d9d 100644 --- a/examples/offscreen-canvas-tiles.js +++ b/examples/offscreen-canvas-tiles.js @@ -1,11 +1,12 @@ import Map from '../src/ol/Map.js'; 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 Worker from 'worker-loader!./offscreen-canvas-tiles.worker.js'; //eslint-disable-line import {compose, create} from '../src/ol/transform.js'; import {createTransformString} from '../src/ol/render/canvas.js'; import {getFontParameters} from '../src/ol/css.js'; +import {createXYZ} from '../src/ol/tilegrid.js'; +import {FullScreen} from '../src/ol/control.js'; const mvtLayerWorker = new Worker(); @@ -14,7 +15,7 @@ mvtLayerWorker.addEventListener('message', event => { if (event.data.action === 'getFontParameters') { getFontParameters(event.data.font, font => { mvtLayerWorker.postMessage({ - action: 'getFontParameters', + action: 'gotFontParameters', font: font }); }); @@ -28,12 +29,12 @@ mvtLayerWorker.addEventListener('message', event => { mvtLayerWorker.postMessage({ action: 'imageLoaded', image: imageBitmap, - iconName: event.data.iconName + src: event.data.src }, [imageBitmap]); }); }); - image.src = 'https://unpkg.com/@mapbox/maki@4.0.0/icons/' + event.data.iconName + '-15.svg'; - loadingImages[event.data.iconName] = true; + image.src = event.data.src; + loadingImages[event.data.src] = true; } } }); @@ -112,10 +113,12 @@ const map = new Map({ ], target: 'map', view: new View({ + resolutions: createXYZ({tileSize: 512}).getResolutions89, center: [0, 0], zoom: 2 }) }); +map.addControl(new FullScreen()); mvtLayerWorker.addEventListener('message', function(message) { if (message.data.action === 'request-render') { map.render(); @@ -125,7 +128,6 @@ mvtLayerWorker.addEventListener('message', function(message) { 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(); diff --git a/examples/offscreen-canvas-tiles.worker.js b/examples/offscreen-canvas-tiles.worker.js new file mode 100644 index 0000000000..d801747de5 --- /dev/null +++ b/examples/offscreen-canvas-tiles.worker.js @@ -0,0 +1,154 @@ +import VectorTileLayer from '../src/ol/layer/VectorTile.js'; +import VectorTileSource from '../src/ol/source/VectorTile.js'; +import MVT from '../src/ol/format/MVT.js'; +import {Projection} from '../src/ol/proj.js'; +import TileQueue from '../src/ol/TileQueue.js'; +import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js'; +import {renderDeclutterItems} from '../src/ol/render.js'; +import styleFunction from 'ol-mapbox-style/dist/stylefunction.js'; +import {inView} from '../src/ol/layer/Layer.js'; + +/** @type {any} */ +const worker = self; + +let frameState, pixelRatio; +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); +} + +const landcover = new VectorTileLayer({ + visible: false, + declutter: true, + maxZoom: 9, + source: new VectorTileSource({ + maxZoom: 9, + format: new MVT(), + url: 'https://api.maptiler.com/tiles/landcover/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB' + }) +}); +const contours = new VectorTileLayer({ + visible: false, + declutter: true, + minZoom: 9, + maxZoom: 14, + source: new VectorTileSource({ + minZoom: 9, + maxZoom: 14, + format: new MVT(), + url: 'https://api.maptiler.com/tiles/contours/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB' + }) +}); +const openmaptiles = new VectorTileLayer({ + visible: false, + declutter: true, + source: new VectorTileSource({ + format: new MVT(), + maxZoom: 14, + url: 'https://api.maptiler.com/tiles/v3/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB' + }) +}); + +const layers = [landcover, contours, openmaptiles]; +let rendererTransform; +layers.forEach(layer => { + layer.once('change', () => { + layer.setVisible(true); + worker.postMessage({action: 'request-render'}); + }); + layer.getRenderer().useContainer = function(target, transform) { + this.containerReused = this.getLayer() !== layers[0]; + target.style = {}; + this.canvas = target; + this.context = target.getContext('2d'); + this.container = { + firstElementChild: target + }; + rendererTransform = transform; + }; +}); + +function getFont(font) { + return font[0] + .replace('Noto Sans', 'serif') + .replace('Roboto', 'sans-serif'); +} + +function loadStyles() { + const styleUrl = 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB'; + fetch(styleUrl).then(data => data.json()).then(styleJson => { + const spriteUrl = styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.json'; + const spriteImageUrl = styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.png'; + fetch(spriteUrl).then(data => data.json()).then(spriteJson => { + styleFunction(landcover, styleJson, 'landcover', undefined, spriteJson, spriteImageUrl, getFont); + styleFunction(contours, styleJson, 'contours', undefined, spriteJson, spriteImageUrl, getFont); + styleFunction(openmaptiles, styleJson, 'openmaptiles', undefined, spriteJson, spriteImageUrl, getFont); + }); + }); +} + +const tileQueue = new TileQueue(getTilePriority, () => { + worker.postMessage({action: 'request-render'}); +}); +const maxTotalLoading = 8; +const maxNewLoads = 2; + +let rendering = false; + +worker.addEventListener('message', event => { + if (event.data.action !== 'render') { + return; + } + frameState = event.data.frameState; + if (!pixelRatio) { + pixelRatio = frameState.pixelRatio; + loadStyles(); + } + frameState.tileQueue = tileQueue; + frameState.viewState.projection.__proto__ = Projection.prototype; + if (rendering) { + return; + } + rendering = true; + requestAnimationFrame(function() { + let rendered = false; + layers.forEach(layer => { + if (inView(layer.getLayerState(), frameState.viewState)) { + rendered = true; + const renderer = layer.getRenderer(); + renderer.renderFrame(frameState, canvas); + } + }); + rendering = false; + if (!rendered) { + return; + } + renderDeclutterItems(frameState, null); + if (tileQueue.getTilesLoading() < maxTotalLoading) { + tileQueue.reprioritize(); // FIXME only call if view has changed + tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); + } + const imageData = canvas.transferToImageBitmap(); + worker.postMessage({ + action: 'rendered', + imageData: imageData, + transform: rendererTransform, + frameState: JSON.parse(JSON.stringify(frameState, getCircularReplacer())) + }, [imageData]); + }); +}); + diff --git a/examples/resources/mapbox-streets-v6-style.js b/examples/resources/mapbox-streets-v6-style.js index e1f0197bf8..afc1d8605d 100644 --- a/examples/resources/mapbox-streets-v6-style.js +++ b/examples/resources/mapbox-streets-v6-style.js @@ -2,20 +2,6 @@ // http://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6.json function createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) { - - let worker; - try { - worker = self.document ? null : self; - worker.addEventListener('message', message => { - if (message.data.type === 'imageLoaded') { - iconCache[message.data.iconName].setImage(new Icon({ - img: message.data.image, - imgSize: [15, 15] - })); - } - }); - } catch (e) {} - var fill = new Fill({color: ''}); var stroke = new Stroke({color: '', width: 1}); var polygon = new Style({fill: fill}); @@ -28,19 +14,11 @@ function createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) { function getIcon(iconName) { var icon = iconCache[iconName]; if (!icon) { - if (!worker) { - icon = new Style({image: new Icon({ - src: 'https://unpkg.com/@mapbox/maki@4.0.0/icons/' + iconName + '-15.svg', - imgSize: [15, 15], - crossOrigin: 'anonymous' - })}); - } else { - icon = new Style({}); - worker.postMessage({ - type: 'loadImage', - iconName: iconName - }); - } + icon = new Style({image: new Icon({ + src: 'https://unpkg.com/@mapbox/maki@4.0.0/icons/' + iconName + '-15.svg', + imgSize: [15, 15], + crossOrigin: 'anonymous' + })}); iconCache[iconName] = icon; } return icon; @@ -331,8 +309,4 @@ function createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) { styles.length = length; return styles; }; -} - -try { - module.exports = createMapboxStreetsV6Style; -} catch (e) {} +} \ No newline at end of file