diff --git a/src/ol/renderer/canvas/Layer.js b/src/ol/renderer/canvas/Layer.js index f7bfa32164..6eedbce160 100644 --- a/src/ol/renderer/canvas/Layer.js +++ b/src/ol/renderer/canvas/Layer.js @@ -120,6 +120,7 @@ class CanvasLayerRenderer extends LayerRenderer { pixelContext.drawImage(image, col, row, 1, 1, 0, 0, 1, 1); data = pixelContext.getImageData(0, 0, 1, 1).data; } catch (err) { + pixelContext = null; return null; } return data; diff --git a/src/ol/renderer/canvas/TileLayer.js b/src/ol/renderer/canvas/TileLayer.js index ff1cb839f2..eb8c65896b 100644 --- a/src/ol/renderer/canvas/TileLayer.js +++ b/src/ol/renderer/canvas/TileLayer.js @@ -208,7 +208,11 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { tileCoord[2] * tileSize[1]) ); - return this.getImageData(tile.getImage(), col, row); + const gutter = Math.round( + tilePixelRatio * source.getGutterForProjection(viewState.projection) + ); + + return this.getImageData(tile.getImage(), col + gutter, row + gutter); } return null; diff --git a/src/ol/webgl/TileTexture.js b/src/ol/webgl/TileTexture.js index 0413ad0d2d..8c457639bf 100644 --- a/src/ol/webgl/TileTexture.js +++ b/src/ol/webgl/TileTexture.js @@ -397,10 +397,22 @@ class TileTexture extends EventTarget { let data; const image = this.tile.getImage(); + const gutter = Math.round(this.tilePixelRatio_ * this.gutter_); try { - pixelContext.drawImage(image, col, row, 1, 1, 0, 0, 1, 1); + pixelContext.drawImage( + image, + col + gutter, + row + gutter, + 1, + 1, + 0, + 0, + 1, + 1 + ); data = pixelContext.getImageData(0, 0, 1, 1).data; } catch (err) { + pixelContext = null; return null; } return data; diff --git a/test/browser/spec/ol/data/wms20.png b/test/browser/spec/ol/data/wms20.png new file mode 100644 index 0000000000..34a5a73d2f Binary files /dev/null and b/test/browser/spec/ol/data/wms20.png differ diff --git a/test/browser/spec/ol/layer/Tile.test.js b/test/browser/spec/ol/layer/Tile.test.js index 756f0028fb..d75688504d 100644 --- a/test/browser/spec/ol/layer/Tile.test.js +++ b/test/browser/spec/ol/layer/Tile.test.js @@ -1,6 +1,6 @@ import TileLayer from '../../../../../src/ol/layer/Tile.js'; import {Map, View} from '../../../../../src/ol/index.js'; -import {OSM, XYZ} from '../../../../../src/ol/source.js'; +import {OSM, TileWMS, XYZ} from '../../../../../src/ol/source.js'; describe('ol/layer/Tile', function () { describe('constructor (defaults)', function () { @@ -78,6 +78,77 @@ describe('ol/layer/Tile', function () { }); }); + describe('gutter', () => { + let map, target, layer, data; + beforeEach((done) => { + target = document.createElement('div'); + target.style.width = '256px'; + target.style.height = '256px'; + document.body.appendChild(target); + + layer = new TileLayer({ + source: new TileWMS({ + params: { + LAYERS: 'layer', + }, + gutter: 20, + url: 'spec/ol/data/wms20.png', + }), + }); + + map = new Map({ + target: target, + pixelRatio: 1, + layers: [layer], + view: new View({ + center: [0, 0], + zoom: 0, + }), + }); + + map.once('rendercomplete', () => done()); + }); + + afterEach(() => { + map.setTarget(null); + document.body.removeChild(target); + }); + + it('gets pixel data', () => { + data = layer.getData([76, 114]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(77); + expect(data[1]).to.be(255); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([76, 118]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(255); + expect(data[1]).to.be(77); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([80, 114]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(255); + expect(data[1]).to.be(77); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([80, 118]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(77); + expect(data[1]).to.be(255); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + }); + }); + describe('frameState.animate after tile transition with layer opacity', function () { let target, map; diff --git a/test/browser/spec/ol/layer/WebGLTile.test.js b/test/browser/spec/ol/layer/WebGLTile.test.js index 9290857a49..a8458f41ce 100644 --- a/test/browser/spec/ol/layer/WebGLTile.test.js +++ b/test/browser/spec/ol/layer/WebGLTile.test.js @@ -1,5 +1,6 @@ import DataTileSource from '../../../../../src/ol/source/DataTile.js'; import Map from '../../../../../src/ol/Map.js'; +import TileWMS from '../../../../../src/ol/source/TileWMS.js'; import View from '../../../../../src/ol/View.js'; import WebGLHelper from '../../../../../src/ol/webgl/Helper.js'; import WebGLTileLayer from '../../../../../src/ol/layer/WebGLTile.js'; @@ -128,6 +129,77 @@ describe('ol/layer/WebGLTile', function () { }); }); + describe('gutter', () => { + let map, target, layer, data; + beforeEach((done) => { + target = document.createElement('div'); + target.style.width = '256px'; + target.style.height = '256px'; + document.body.appendChild(target); + + layer = new WebGLTileLayer({ + source: new TileWMS({ + params: { + LAYERS: 'layer', + }, + gutter: 20, + url: 'spec/ol/data/wms20.png', + }), + }); + + map = new Map({ + target: target, + pixelRatio: 1, + layers: [layer], + view: new View({ + center: [0, 0], + zoom: 0, + }), + }); + + map.once('rendercomplete', () => done()); + }); + + afterEach(() => { + map.setTarget(null); + document.body.removeChild(target); + }); + + it('gets pixel data', () => { + data = layer.getData([76, 114]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(77); + expect(data[1]).to.be(255); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([76, 118]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(255); + expect(data[1]).to.be(77); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([80, 114]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(255); + expect(data[1]).to.be(77); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + + data = layer.getData([80, 118]); + expect(data).to.be.a(Uint8ClampedArray); + expect(data.length).to.be(4); + expect(data[0]).to.be(77); + expect(data[1]).to.be(255); + expect(data[2]).to.be(77); + expect(data[3]).to.be(179); + }); + }); + describe('dispose()', () => { it('calls dispose on the renderer', () => { const renderer = layer.getRenderer();