From ee5553debb3f13730c986a0b8662cffa412863c2 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Sun, 30 May 2021 19:06:36 +0100 Subject: [PATCH 1/7] Rework TileDebug to fix reprojection issue and allow {-y} Add setImage method to ol/ImageTile --- src/ol/ImageTile.js | 16 +++++ src/ol/source/TileDebug.js | 130 +++++++------------------------------ 2 files changed, 40 insertions(+), 106 deletions(-) diff --git a/src/ol/ImageTile.js b/src/ol/ImageTile.js index f6367490ac..741982fac3 100644 --- a/src/ol/ImageTile.js +++ b/src/ol/ImageTile.js @@ -72,6 +72,22 @@ class ImageTile extends Tile { return this.image_; } + /** + * Sets an HTML image element for this tile (may be a Canvas or preloaded Image). + * @param {HTMLCanvasElement|HTMLImageElement} element Element. + * @api + */ + setImage(element) { + // asynchronous to accomodate reprojection listeners + const tile = this; + setTimeout(function () { + tile.image_ = element; + tile.state = TileState.LOADED; + tile.unlistenImage_(); + tile.changed(); + }, 0); + } + /** * Tracks loading or read errors. * diff --git a/src/ol/source/TileDebug.js b/src/ol/source/TileDebug.js index 36353da531..7f14bcf9a3 100644 --- a/src/ol/source/TileDebug.js +++ b/src/ol/source/TileDebug.js @@ -2,82 +2,10 @@ * @module ol/source/TileDebug */ -import Tile from '../Tile.js'; -import TileState from '../TileState.js'; import XYZ from './XYZ.js'; import {createCanvasContext2D} from '../dom.js'; -import {getKeyZXY} from '../tilecoord.js'; import {toSize} from '../size.js'; -class LabeledTile extends Tile { - /** - * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. - * @param {import("../size.js").Size} tileSize Tile size. - * @param {string} text Text. - */ - constructor(tileCoord, tileSize, text) { - super(tileCoord, TileState.LOADED); - - /** - * @private - * @type {import("../size.js").Size} - */ - this.tileSize_ = tileSize; - - /** - * @private - * @type {string} - */ - this.text_ = text; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - } - - /** - * Get the image element for this tile. - * @return {HTMLCanvasElement} Image. - */ - getImage() { - if (this.canvas_) { - return this.canvas_; - } else { - const tileSize = this.tileSize_; - const context = createCanvasContext2D(tileSize[0], tileSize[1]); - - context.strokeStyle = 'grey'; - context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); - - context.fillStyle = 'grey'; - context.strokeStyle = 'white'; - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.font = '24px sans-serif'; - context.lineWidth = 4; - context.strokeText( - this.text_, - tileSize[0] / 2, - tileSize[1] / 2, - tileSize[0] - ); - context.fillText( - this.text_, - tileSize[0] / 2, - tileSize[1] / 2, - tileSize[0] - ); - - this.canvas_ = context.canvas; - return context.canvas; - } - } - - load() {} -} - /** * @typedef {Object} Options * @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Optional projection. @@ -88,6 +16,8 @@ class LabeledTile extends Tile { * the view resolution does not match any resolution of the tile source. If 0, the nearest * resolution will be used. If 1, the nearest lower resolution will be used. If -1, the * nearest higher resolution will be used. + * @property {string} [template='z:{z} x:{x} y:{y}'] Template for labeling the tiles. + * Should include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders. */ /** @@ -95,8 +25,6 @@ class LabeledTile extends Tile { * A pseudo tile source, which does not fetch tiles from a server, but renders * a grid outline for the tile grid/projection along with the coordinates for * each tile. See examples/canvas-tiles for an example. - * - * Uses Canvas context2d, so requires Canvas support. * @api */ class TileDebug extends XYZ { @@ -115,39 +43,29 @@ class TileDebug extends XYZ { tileGrid: options.tileGrid, wrapX: options.wrapX !== undefined ? options.wrapX : true, zDirection: options.zDirection, - }); - } + url: options.template || 'z:{z} x:{x} y:{y}', + tileLoadFunction: (tile, text) => { + const z = tile.getTileCoord()[0]; + const tileSize = toSize(this.tileGrid.getTileSize(z)); + const context = createCanvasContext2D(tileSize[0], tileSize[1]); - /** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @return {!LabeledTile} Tile. - */ - getTile(z, x, y) { - const tileCoordKey = getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!LabeledTile} */ (this.tileCache.get(tileCoordKey)); - } else { - const tileSize = toSize(this.tileGrid.getTileSize(z)); - const tileCoord = [z, x, y]; - const textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord); - let text; - if (textTileCoord) { - text = - 'z:' + - textTileCoord[0] + - ' x:' + - textTileCoord[1] + - ' y:' + - textTileCoord[2]; - } else { - text = 'none'; - } - const tile = new LabeledTile(tileCoord, tileSize, text); - this.tileCache.set(tileCoordKey, tile); - return tile; - } + context.strokeStyle = 'grey'; + context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); + + context.fillStyle = 'grey'; + context.strokeStyle = 'white'; + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.font = '24px sans-serif'; + context.lineWidth = 4; + context.strokeText(text, tileSize[0] / 2, tileSize[1] / 2, tileSize[0]); + context.fillText(text, tileSize[0] / 2, tileSize[1] / 2, tileSize[0]); + + /** @type {import("../ImageTile.js").default} */ (tile).setImage( + context.canvas + ); + }, + }); } } From 6304b56501290a3c63a0448040ccb7f6ed3fb25b Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Sat, 19 Jun 2021 11:55:51 +0100 Subject: [PATCH 2/7] New example --- examples/canvas-tiles-tms.html | 14 ++++++++ examples/canvas-tiles-tms.js | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 examples/canvas-tiles-tms.html create mode 100644 examples/canvas-tiles-tms.js diff --git a/examples/canvas-tiles-tms.html b/examples/canvas-tiles-tms.html new file mode 100644 index 0000000000..28fc084ab7 --- /dev/null +++ b/examples/canvas-tiles-tms.html @@ -0,0 +1,14 @@ +--- +layout: example.html +title: Custom Canvas Tiles +shortdesc: Renders tiles with TMS coordinates for debugging. +docs: > + The black grid tiles are generated on the client with an HTML5 canvas. + The displayed TMS tile coordinates are produced using a custom template + for TMS, the vector tile source's 512 pixel tile grid and the + zDirection setting for vector tiles. + Notice how the country polygons can be split between tiles and vector + labels may appear in each tile. +tags: "layers, vector tiles, tms, canvas" +--- +
diff --git a/examples/canvas-tiles-tms.js b/examples/canvas-tiles-tms.js new file mode 100644 index 0000000000..e7d37c8a8e --- /dev/null +++ b/examples/canvas-tiles-tms.js @@ -0,0 +1,61 @@ +import MVT from '../src/ol/format/MVT.js'; +import Map from '../src/ol/Map.js'; +import TileDebug from '../src/ol/source/TileDebug.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import VectorTileLayer from '../src/ol/layer/VectorTile.js'; +import VectorTileSource from '../src/ol/source/VectorTile.js'; +import View from '../src/ol/View.js'; +import {Fill, Stroke, Style, Text} from '../src/ol/style.js'; + +const style = new Style({ + fill: new Fill({ + color: 'rgba(255, 255, 255, 0.6)', + }), + stroke: new Stroke({ + color: '#319FD3', + width: 1, + }), + text: new Text({ + font: '12px Calibri,sans-serif', + fill: new Fill({ + color: '#000', + }), + stroke: new Stroke({ + color: '#fff', + width: 3, + }), + }), +}); + +const vtLayer = new VectorTileLayer({ + declutter: true, + source: new VectorTileSource({ + maxZoom: 15, + format: new MVT(), + url: + 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' + + 'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf', + }), + style: function (feature) { + style.getText().setText(feature.get('name')); + return style; + }, +}); + +const debugLayer = new TileLayer({ + source: new TileDebug({ + template: 'z:{z} x:{x} y:{-y}', + projection: vtLayer.getSource().getProjection(), + tileGrid: vtLayer.getSource().getTileGrid(), + zDirection: 1, + }), +}); + +const map = new Map({ + layers: [vtLayer, debugLayer], + target: 'map', + view: new View({ + center: [0, 6000000], + zoom: 4, + }), +}); From db1fa9b659c2e2436917050d241ef67dc44ebdc0 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Sat, 19 Jun 2021 18:32:19 +0100 Subject: [PATCH 3/7] New test --- .../cases/reproj-tile-4326-debug/expected.png | Bin 0 -> 39505 bytes .../cases/reproj-tile-4326-debug/main.js | 49 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/rendering/cases/reproj-tile-4326-debug/expected.png create mode 100644 test/rendering/cases/reproj-tile-4326-debug/main.js diff --git a/test/rendering/cases/reproj-tile-4326-debug/expected.png b/test/rendering/cases/reproj-tile-4326-debug/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..7e5f6784b33ddf77e52bd7d41cade67df81436d7 GIT binary patch literal 39505 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 Date: Fri, 25 Jun 2021 12:42:49 +0100 Subject: [PATCH 4/7] handle synchronous loading correctly --- src/ol/reproj/Tile.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ol/reproj/Tile.js b/src/ol/reproj/Tile.js index 02fe5c75db..a44fcba169 100644 --- a/src/ol/reproj/Tile.js +++ b/src/ol/reproj/Tile.js @@ -334,15 +334,15 @@ class ReprojTile extends Tile { }.bind(this) ); - this.sourceTiles_.forEach(function (tile, i, arr) { - const state = tile.getState(); - if (state == TileState.IDLE) { - tile.load(); - } - }); - if (leftToLoad === 0) { setTimeout(this.reproject_.bind(this), 0); + } else { + this.sourceTiles_.forEach(function (tile, i, arr) { + const state = tile.getState(); + if (state == TileState.IDLE) { + tile.load(); + } + }); } } } From d8a5b91ad5203bc0f6032cd5ffc7c81ce4f71984 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Fri, 25 Jun 2021 12:42:52 +0100 Subject: [PATCH 5/7] Make setImage() synchronous --- src/ol/ImageTile.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ol/ImageTile.js b/src/ol/ImageTile.js index 741982fac3..b7f440afa2 100644 --- a/src/ol/ImageTile.js +++ b/src/ol/ImageTile.js @@ -78,14 +78,10 @@ class ImageTile extends Tile { * @api */ setImage(element) { - // asynchronous to accomodate reprojection listeners - const tile = this; - setTimeout(function () { - tile.image_ = element; - tile.state = TileState.LOADED; - tile.unlistenImage_(); - tile.changed(); - }, 0); + this.image_ = element; + this.state = TileState.LOADED; + this.unlistenImage_(); + this.changed(); } /** From f7bd8102c53e1eca463da788d56c79fc93ca2224 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Tue, 29 Jun 2021 11:01:30 +0100 Subject: [PATCH 6/7] Add Show tile coordinates option --- examples/reprojection-by-code.html | 28 ++++++++++++++---------- examples/reprojection-by-code.js | 34 +++++++++++++++++------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/examples/reprojection-by-code.html b/examples/reprojection-by-code.html index df386d4864..d09702f50f 100644 --- a/examples/reprojection-by-code.html +++ b/examples/reprojection-by-code.html @@ -10,18 +10,24 @@ tags: "reprojection, projection, proj4js, epsg.io, graticule" ---
- + -
- - -
+
+
+ +      + +      +
diff --git a/examples/reprojection-by-code.js b/examples/reprojection-by-code.js index 2926a94486..2e169c1340 100644 --- a/examples/reprojection-by-code.js +++ b/examples/reprojection-by-code.js @@ -2,7 +2,7 @@ import Graticule from '../src/ol/layer/Graticule.js'; import Map from '../src/ol/Map.js'; import OSM from '../src/ol/source/OSM.js'; import Stroke from '../src/ol/style/Stroke.js'; -import TileImage from '../src/ol/source/TileImage.js'; +import TileDebug from '../src/ol/source/TileDebug.js'; import TileLayer from '../src/ol/layer/Tile.js'; import View from '../src/ol/View.js'; import proj4 from 'proj4'; @@ -10,6 +10,16 @@ import {applyTransform} from '../src/ol/extent.js'; import {get as getProjection, getTransform} from '../src/ol/proj.js'; import {register} from '../src/ol/proj/proj4.js'; +const osmSource = new OSM(); + +const debugLayer = new TileLayer({ + source: new TileDebug({ + tileGrid: osmSource.getTileGrid(), + projection: osmSource.getProjection(), + }), + visible: false, +}); + const graticule = new Graticule({ // the style to use for the lines, optional. strokeStyle: new Stroke({ @@ -25,8 +35,9 @@ const graticule = new Graticule({ const map = new Map({ layers: [ new TileLayer({ - source: new OSM(), + source: osmSource, }), + debugLayer, graticule, ], target: 'map', @@ -41,6 +52,7 @@ const queryInput = document.getElementById('epsg-query'); const searchButton = document.getElementById('epsg-search'); const resultSpan = document.getElementById('epsg-result'); const renderEdgesCheckbox = document.getElementById('render-edges'); +const showTilesCheckbox = document.getElementById('show-tiles'); const showGraticuleCheckbox = document.getElementById('show-graticule'); function setProjection(code, name, proj4def, bbox) { @@ -125,22 +137,14 @@ searchButton.onclick = function (event) { }; /** - * Handle checkbox change event. + * Handle checkbox change events. */ renderEdgesCheckbox.onchange = function () { - map.getLayers().forEach(function (layer) { - if (layer instanceof TileLayer) { - const source = layer.getSource(); - if (source instanceof TileImage) { - source.setRenderReprojectionEdges(renderEdgesCheckbox.checked); - } - } - }); + osmSource.setRenderReprojectionEdges(renderEdgesCheckbox.checked); +}; +showTilesCheckbox.onchange = function () { + debugLayer.setVisible(showTilesCheckbox.checked); }; - -/** - * Handle checkbox change event. - */ showGraticuleCheckbox.onchange = function () { graticule.setVisible(showGraticuleCheckbox.checked); }; From be6c757ff60d0a06c0351ebe19732047c09a3377 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 29 Jun 2021 14:19:58 +0200 Subject: [PATCH 7/7] Don't add setImage to the API --- src/ol/ImageTile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ol/ImageTile.js b/src/ol/ImageTile.js index b7f440afa2..a2fce7f973 100644 --- a/src/ol/ImageTile.js +++ b/src/ol/ImageTile.js @@ -75,7 +75,6 @@ class ImageTile extends Tile { /** * Sets an HTML image element for this tile (may be a Canvas or preloaded Image). * @param {HTMLCanvasElement|HTMLImageElement} element Element. - * @api */ setImage(element) { this.image_ = element;