diff --git a/examples/interpolation.html b/examples/interpolation.html index 64d942a17e..191c123dc6 100644 --- a/examples/interpolation.html +++ b/examples/interpolation.html @@ -6,7 +6,7 @@ docs: > Example of data resampling when using raster DEM (digital elevation model) data. The interpolate: false setting is used to disable interpolation of data values during reprojection and rendering. Elevation data is - calculated from the pixel value returned by forEachLayerAtPixel. For comparison a second map + calculated from the pixel value returned by getData. For comparison a second map reprojected with interpolation enabled returns inaccurate elevations which are very noticeable close to 3107 meters due to how elevation is calculated from the pixel value. tags: "disable image interpolation, xyz, maptiler, reprojection" @@ -21,7 +21,7 @@ cloak:
@@ -31,7 +31,7 @@ cloak:
diff --git a/examples/interpolation.js b/examples/interpolation.js index b4ca91872f..cf1c23f7f6 100644 --- a/examples/interpolation.js +++ b/examples/interpolation.js @@ -9,8 +9,6 @@ const attributions = '© OpenStreetMap contributors'; const notInterpolated = new TileLayer({ - // specify className so forEachLayerAtPixel can distinguish layers - className: 'ol-layer-dem', source: new XYZ({ attributions: attributions, url: @@ -51,39 +49,25 @@ const map2 = new Map({ view: view, }); +function getHeight(rgba) { + return -10000 + (rgba[0] * 256 * 256 + rgba[1] * 256 + rgba[2]) * 0.1; +} + const info1 = document.getElementById('info1'); const info2 = document.getElementById('info2'); - const showElevations = function (evt) { if (evt.dragging) { return; } - map1.forEachLayerAtPixel( - evt.pixel, - function (layer, pixel) { - const height = - -10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1; - info1.innerText = height.toFixed(1); - }, - { - layerFilter: function (layer) { - return layer === notInterpolated; - }, - } - ); - map2.forEachLayerAtPixel( - evt.pixel, - function (layer, pixel) { - const height = - -10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1; - info2.innerText = height.toFixed(1); - }, - { - layerFilter: function (layer) { - return layer === interpolated; - }, - } - ); + const notInterpolatedPixel = notInterpolated.getData(evt.pixel); + info1.innerText = notInterpolatedPixel + ? getHeight(notInterpolatedPixel).toFixed(1) + : '-'; + + const interpolatedPixel = interpolated.getData(evt.pixel); + info2.innerText = interpolatedPixel + ? getHeight(interpolatedPixel).toFixed(1) + : '-'; }; map1.on('pointermove', showElevations); diff --git a/src/ol/PluggableMap.js b/src/ol/PluggableMap.js index 3c8aa39df1..3fa410d5a1 100644 --- a/src/ol/PluggableMap.js +++ b/src/ol/PluggableMap.js @@ -693,51 +693,6 @@ class PluggableMap extends BaseObject { return layers; } - /** - * Please the `layer.getData()` method for {@link module:ol/layer/Tile~TileLayer#getData tile layers} or - * {@link module:ol/layer/Image~ImageLayer#getData image layers} instead of using this method. - * - * Detect layers that have a color value at a pixel on the viewport, and - * execute a callback with each matching layer. Layers included in the - * detection can be configured through `opt_layerFilter`. - * - * Note: In maps with more than one layer, this method will typically return pixel data - * representing the composed image of all layers visible at the given pixel – because layers - * will generally share the same rendering context. To force layers to render separately, and - * to get pixel data representing only one layer at a time, you can assign each layer a unique - * `className` in its constructor. - * - * @param {import("./pixel.js").Pixel} pixel Pixel. - * @param {function(this: S, import("./layer/Layer.js").default, (Uint8ClampedArray|Uint8Array)): T} callback - * Layer callback. This callback will receive two arguments: first is the - * {@link module:ol/layer/Layer~Layer layer}, second argument is an array representing - * [R, G, B, A] pixel values (0 - 255) and will be `null` for layer types - * that do not currently support this argument. To stop detection, callback - * functions can return a truthy value. - * @param {AtPixelOptions} [opt_options] Configuration options. - * @return {T|undefined} Callback result, i.e. the return value of last - * callback execution, or the first truthy callback return value. - * @template S,T - * @api - * @deprecated - */ - forEachLayerAtPixel(pixel, callback, opt_options) { - if (!this.frameState_ || !this.renderer_) { - return; - } - const options = opt_options || {}; - const hitTolerance = - options.hitTolerance !== undefined ? options.hitTolerance : 0; - const layerFilter = options.layerFilter || TRUE; - return this.renderer_.forEachLayerAtPixel( - pixel, - this.frameState_, - hitTolerance, - callback, - layerFilter - ); - } - /** * Detect if features intersect a pixel on the viewport. Layers included in the * detection can be configured through `opt_layerFilter`. diff --git a/src/ol/layer/Layer.js b/src/ol/layer/Layer.js index d481d90c6a..c40412be60 100644 --- a/src/ol/layer/Layer.js +++ b/src/ol/layer/Layer.js @@ -83,11 +83,6 @@ import {listen, unlistenByKey} from '../events.js'; * * A generic `change` event is fired when the state of the source changes. * - * Please note that for performance reasons several layers might get rendered to - * the same HTML element, which will cause {@link import("../PluggableMap.js").default#forEachLayerAtPixel map.forEachLayerAtPixel()} to - * give false positives. To avoid this, apply different `className` properties to the - * layers at creation time. - * * @fires import("../render/Event.js").RenderEvent#prerender * @fires import("../render/Event.js").RenderEvent#postrender * @@ -310,8 +305,7 @@ class Layer extends BaseLayer { /** * Sets the layer to be rendered on top of other layers on a map. The map will - * not manage this layer in its layers collection, and the callback in - * {@link module:ol/Map~Map#forEachLayerAtPixel} will receive `null` as layer. This + * not manage this layer in its layers collection. This * is useful for temporary layers. To remove an unmanaged layer from the map, * use `#setMap(null)`. * diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js index 3ef0b77a16..b4c5ed7284 100644 --- a/src/ol/renderer/Composite.js +++ b/src/ol/renderer/Composite.js @@ -149,50 +149,6 @@ class CompositeMapRenderer extends MapRenderer { this.scheduleExpireIconCache(frameState); } - - /** - * @param {import("../pixel.js").Pixel} pixel Pixel. - * @param {import("../PluggableMap.js").FrameState} frameState FrameState. - * @param {number} hitTolerance Hit tolerance in pixels. - * @param {function(import("../layer/Layer.js").default, (Uint8ClampedArray|Uint8Array)): T} callback Layer - * callback. - * @param {function(import("../layer/Layer.js").default): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @return {T|undefined} Callback result. - * @template T - */ - forEachLayerAtPixel(pixel, frameState, hitTolerance, callback, layerFilter) { - const viewState = frameState.viewState; - - const layerStates = frameState.layerStatesArray; - const numLayers = layerStates.length; - - for (let i = numLayers - 1; i >= 0; --i) { - const layerState = layerStates[i]; - const layer = layerState.layer; - if ( - layer.hasRenderer() && - inView(layerState, viewState) && - layerFilter(layer) - ) { - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - if (data) { - const result = callback(layer, data); - if (result) { - return result; - } - } - } - } - return undefined; - } } export default CompositeMapRenderer; diff --git a/src/ol/renderer/Layer.js b/src/ol/renderer/Layer.js index a1b73dea0e..fbce025e07 100644 --- a/src/ol/renderer/Layer.js +++ b/src/ol/renderer/Layer.js @@ -133,19 +133,6 @@ class LayerRenderer extends Observable { return undefined; } - /** - * @abstract - * @param {import("../pixel.js").Pixel} pixel Pixel. - * @param {import("../PluggableMap.js").FrameState} frameState FrameState. - * @param {number} hitTolerance Hit tolerance in pixels. - * @return {Uint8ClampedArray|Uint8Array} The result. If there is no data at the pixel - * location, null will be returned. If there is data, but pixel values cannot be - * returned, and empty array will be returned. - */ - getDataAtPixel(pixel, frameState, hitTolerance) { - return null; - } - /** * @return {LayerType} Layer. */ diff --git a/src/ol/renderer/Map.js b/src/ol/renderer/Map.js index 8252ea2e85..cff20012ab 100644 --- a/src/ol/renderer/Map.js +++ b/src/ol/renderer/Map.js @@ -170,24 +170,6 @@ class MapRenderer extends Disposable { return result; } - /** - * @abstract - * @param {import("../pixel.js").Pixel} pixel Pixel. - * @param {import("../PluggableMap.js").FrameState} frameState FrameState. - * @param {number} hitTolerance Hit tolerance in pixels. - * @param {function(import("../layer/Layer.js").default, (Uint8ClampedArray|Uint8Array)): T} callback Layer - * callback. - * @param {function(import("../layer/Layer.js").default): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @return {T|undefined} Callback result. - * @template T - */ - forEachLayerAtPixel(pixel, frameState, hitTolerance, callback, layerFilter) { - return abstract(); - } - /** * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. * @param {import("../PluggableMap.js").FrameState} frameState FrameState. diff --git a/src/ol/renderer/canvas/Layer.js b/src/ol/renderer/canvas/Layer.js index 7852bcf6cb..c472196adc 100644 --- a/src/ol/renderer/canvas/Layer.js +++ b/src/ol/renderer/canvas/Layer.js @@ -10,15 +10,14 @@ import { create as createTransform, } from '../../transform.js'; import {asArray} from '../../color.js'; +import {createCanvasContext2D} from '../../dom.js'; +import {equals} from '../../array.js'; import { - containsCoordinate, getBottomLeft, getBottomRight, getTopLeft, getTopRight, } from '../../extent.js'; -import {createCanvasContext2D} from '../../dom.js'; -import {equals} from '../../array.js'; /** * @type {Array} @@ -315,65 +314,6 @@ class CanvasLayerRenderer extends LayerRenderer { ); } - /** - * @param {import("../../pixel.js").Pixel} pixel Pixel. - * @param {import("../../PluggableMap.js").FrameState} frameState FrameState. - * @param {number} hitTolerance Hit tolerance in pixels. - * @return {Uint8ClampedArray|Uint8Array} The result. If there is no data at the pixel - * location, null will be returned. If there is data, but pixel values cannot be - * returned, and empty array will be returned. - */ - getDataAtPixel(pixel, frameState, hitTolerance) { - const renderPixel = applyTransform( - this.inversePixelTransform, - pixel.slice() - ); - const context = this.context; - - const layer = this.getLayer(); - const layerExtent = layer.getExtent(); - if (layerExtent) { - const renderCoordinate = applyTransform( - frameState.pixelToCoordinateTransform, - pixel.slice() - ); - - /** get only data inside of the layer extent */ - if (!containsCoordinate(layerExtent, renderCoordinate)) { - return null; - } - } - - const x = Math.round(renderPixel[0]); - const y = Math.round(renderPixel[1]); - let pixelContext = this.pixelContext_; - if (!pixelContext) { - const pixelCanvas = document.createElement('canvas'); - pixelCanvas.width = 1; - pixelCanvas.height = 1; - pixelContext = pixelCanvas.getContext('2d'); - this.pixelContext_ = pixelContext; - } - pixelContext.clearRect(0, 0, 1, 1); - let data; - try { - pixelContext.drawImage(context.canvas, x, y, 1, 1, 0, 0, 1, 1); - data = pixelContext.getImageData(0, 0, 1, 1).data; - } catch (err) { - if (err.name === 'SecurityError') { - // tainted canvas, we assume there is data at the given pixel (although there might not be) - this.pixelContext_ = null; - return new Uint8Array(); - } - return data; - } - - if (data[3] === 0) { - return null; - } - return data; - } - /** * Clean up. */ diff --git a/src/ol/renderer/webgl/Layer.js b/src/ol/renderer/webgl/Layer.js index 1587e8c9d8..8ce020d53d 100644 --- a/src/ol/renderer/webgl/Layer.js +++ b/src/ol/renderer/webgl/Layer.js @@ -7,11 +7,9 @@ import RenderEvent from '../../render/Event.js'; import RenderEventType from '../../render/EventType.js'; import WebGLHelper from '../../webgl/Helper.js'; import { - apply as applyTransform, compose as composeTransform, create as createTransform, } from '../../transform.js'; -import {containsCoordinate} from '../../extent.js'; /** * @typedef {Object} PostProcessesOptions @@ -259,68 +257,6 @@ class WebGLLayerRenderer extends LayerRenderer { postRender(context, frameState) { this.dispatchRenderEvent_(RenderEventType.POSTRENDER, context, frameState); } - - /** - * @param {import("../../pixel.js").Pixel} pixel Pixel. - * @param {import("../../PluggableMap.js").FrameState} frameState FrameState. - * @param {number} hitTolerance Hit tolerance in pixels. - * @return {Uint8ClampedArray|Uint8Array} The result. If there is no data at the pixel - * location, null will be returned. If there is data, but pixel values cannot be - * returned, and empty array will be returned. - */ - getDataAtPixel(pixel, frameState, hitTolerance) { - const renderPixel = applyTransform( - [frameState.pixelRatio, 0, 0, frameState.pixelRatio, 0, 0], - pixel.slice() - ); - const gl = this.helper.getGL(); - if (!gl) { - return null; - } - const layer = this.getLayer(); - const layerExtent = layer.getExtent(); - if (layerExtent) { - const renderCoordinate = applyTransform( - frameState.pixelToCoordinateTransform, - pixel.slice() - ); - - /** get only data inside of the layer extent */ - if (!containsCoordinate(layerExtent, renderCoordinate)) { - return null; - } - } - - const attributes = gl.getContextAttributes(); - if (!attributes || !attributes.preserveDrawingBuffer) { - // we assume there is data at the given pixel (although there might not be) - return new Uint8Array(); - } - - const x = Math.round(renderPixel[0]); - const y = Math.round(renderPixel[1]); - let pixelContext = this.pixelContext_; - if (!pixelContext) { - const pixelCanvas = document.createElement('canvas'); - pixelCanvas.width = 1; - pixelCanvas.height = 1; - pixelContext = pixelCanvas.getContext('2d'); - this.pixelContext_ = pixelContext; - } - pixelContext.clearRect(0, 0, 1, 1); - let data; - try { - pixelContext.drawImage(gl.canvas, x, y, 1, 1, 0, 0, 1, 1); - data = pixelContext.getImageData(0, 0, 1, 1).data; - } catch (err) { - return data; - } - - if (data[3] === 0) { - return null; - } - return data; - } } export default WebGLLayerRenderer; diff --git a/test/browser/spec/ol/Map.test.js b/test/browser/spec/ol/Map.test.js index f52c459bc8..a6ca16fcd0 100644 --- a/test/browser/spec/ol/Map.test.js +++ b/test/browser/spec/ol/Map.test.js @@ -19,7 +19,6 @@ import PinchZoom from '../../../../src/ol/interaction/PinchZoom.js'; import Property from '../../../../src/ol/layer/Property.js'; import Select from '../../../../src/ol/interaction/Select.js'; import TileLayer from '../../../../src/ol/layer/Tile.js'; -import TileLayerRenderer from '../../../../src/ol/renderer/canvas/TileLayer.js'; import VectorLayer from '../../../../src/ol/layer/Vector.js'; import VectorSource from '../../../../src/ol/source/Vector.js'; import VectorTileLayer from '../../../../src/ol/layer/VectorTile.js'; @@ -1027,66 +1026,6 @@ describe('ol/Map', function () { }); }); - describe('#forEachLayerAtPixel()', function () { - let target, map, original, log; - - beforeEach(function (done) { - log = []; - original = TileLayerRenderer.prototype.getDataAtPixel; - TileLayerRenderer.prototype.getDataAtPixel = function (pixel) { - log.push(pixel.slice()); - }; - - target = document.createElement('div'); - const style = target.style; - style.position = 'absolute'; - style.left = '-1000px'; - style.top = '-1000px'; - style.width = '360px'; - style.height = '180px'; - document.body.appendChild(target); - - map = new Map({ - target: target, - view: new View({ - center: [0, 0], - zoom: 1, - }), - layers: [ - new TileLayer({ - source: new XYZ(), - }), - new TileLayer({ - source: new XYZ(), - }), - new TileLayer({ - source: new XYZ(), - }), - ], - }); - - map.once('postrender', function () { - done(); - }); - }); - - afterEach(function () { - TileLayerRenderer.prototype.getDataAtPixel = original; - map.dispose(); - document.body.removeChild(target); - log = null; - }); - - it('calls each layer renderer with the same pixel', function () { - const pixel = [10, 20]; - map.forEachLayerAtPixel(pixel, function () {}); - expect(log.length).to.equal(3); - expect(log[0].length).to.equal(2); - expect(log[0]).to.eql(log[1]); - expect(log[1]).to.eql(log[2]); - }); - }); - describe('#render()', function () { let target, map; diff --git a/test/browser/spec/ol/renderer/canvas/ImageLayer.test.js b/test/browser/spec/ol/renderer/canvas/ImageLayer.test.js index be0db8fbfe..87befaa68a 100644 --- a/test/browser/spec/ol/renderer/canvas/ImageLayer.test.js +++ b/test/browser/spec/ol/renderer/canvas/ImageLayer.test.js @@ -13,8 +13,10 @@ import View from '../../../../../../src/ol/View.js'; import {get as getProj} from '../../../../../../src/ol/proj.js'; describe('ol/renderer/canvas/ImageLayer', function () { - describe('#forEachLayerAtCoordinate', function () { + describe('#getData', function () { let map, target, source; + /** @type {ImageLayer} */ + let layer; beforeEach(function (done) { const projection = new Projection({ code: 'custom-image', @@ -30,14 +32,13 @@ describe('ol/renderer/canvas/ImageLayer', function () { projection: projection, imageExtent: [0, 0, 20, 20], }); + layer = new ImageLayer({ + source: source, + }); map = new Map({ pixelRatio: 1, target: target, - layers: [ - new ImageLayer({ - source: source, - }), - ], + layers: [layer], view: new View({ projection: projection, center: [10, 10], @@ -57,19 +58,13 @@ describe('ol/renderer/canvas/ImageLayer', function () { it('properly detects pixels', function () { map.renderSync(); - let has = false; - function hasLayer() { - has = true; - } - map.forEachLayerAtPixel([20, 80], hasLayer); - expect(has).to.be(true); - has = false; - map.forEachLayerAtPixel([10, 90], hasLayer); - expect(has).to.be(false); + + expect(layer.getData([20, 80])[3]).to.not.be(0); + expect(layer.getData([10, 90])[3]).to.be(0); }); }); - describe('#forEachLayerAtPixel Image CORS', function () { + describe('#getData Image CORS', function () { let map, target, imageExtent, @@ -133,34 +128,22 @@ describe('ol/renderer/canvas/ImageLayer', function () { document.body.removeChild(target); }); - it('should detect pixels even if there is no color because neither crossOrigin or extent is set', function () { + it('should not detect pixels when crossOrigin is not set', function () { imageLayerCross.setVisible(false); imageLayer.setVisible(true); map.renderSync(); - let has = false; - function hasLayer() { - has = true; - } - map.forEachLayerAtPixel([50, 50], hasLayer); - expect(has).to.be(true); - has = false; - map.forEachLayerAtPixel([10, 10], hasLayer); - expect(has).to.be(true); + + expect(imageLayer.getData([50, 50])).to.be(null); + expect(imageLayer.getData([10, 10])).to.be(null); }); it('should not detect pixels outside of the layer extent with crossOrigin set', function () { imageLayerCross.setVisible(true); imageLayer.setVisible(false); map.renderSync(); - let has = false; - function hasLayer() { - has = true; - } - map.forEachLayerAtPixel([50, 50], hasLayer); - expect(has).to.be(true); - has = false; - map.forEachLayerAtPixel([10, 10], hasLayer); - expect(has).to.be(false); + + expect(imageLayerCross.getData([50, 50])).to.not.be(null); + expect(imageLayerCross.getData([10, 10])).to.be(null); }); it('should not detect pixels outside of the layer extent with extent set', function () { @@ -168,87 +151,9 @@ describe('ol/renderer/canvas/ImageLayer', function () { imageLayerCross.setExtent(imageExtent); imageLayer.setVisible(false); map.renderSync(); - let has = false; - function hasLayer() { - has = true; - } - map.forEachLayerAtPixel([50, 50], hasLayer); - expect(has).to.be(true); - has = false; - map.forEachLayerAtPixel([10, 10], hasLayer); - expect(has).to.be(false); - }); - }); - describe('#getDataAtPixel', function () { - let map, target, source, imageLayer; - beforeEach(function (done) { - const projection = new Projection({ - code: 'custom-image', - units: 'pixels', - extent: [0, 0, 200, 200], - }); - target = document.createElement('div'); - target.style.width = '100px'; - target.style.height = '100px'; - document.body.appendChild(target); - const imageExtent = [0, 0, 20, 20]; - source = new Static({ - url: 'spec/ol/data/dot.png', - projection: projection, - imageExtent: imageExtent, - }); - imageLayer = new ImageLayer({ - source: source, - extent: imageExtent, - }); - map = new Map({ - pixelRatio: 1, - target: target, - layers: [imageLayer], - view: new View({ - projection: projection, - center: [10, 10], - zoom: 1, - maxZoom: 8, - }), - }); - source.on('imageloadend', function () { - done(); - }); - }); - - afterEach(function () { - map.setTarget(null); - document.body.removeChild(target); - }); - - it('should not detect pixels outside of the layer extent', function () { - map.renderSync(); - const pixel = [10, 10]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = imageLayer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data).to.be(null); - }); - - it('should detect pixels in the layer extent', function () { - map.renderSync(); - const pixel = [50, 50]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = imageLayer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data.length > 0).to.be(true); + expect(imageLayerCross.getData([50, 50])).to.not.be(null); + expect(imageLayerCross.getData([10, 10])).to.be(null); }); }); diff --git a/test/browser/spec/ol/renderer/webgl/Layer.test.js b/test/browser/spec/ol/renderer/webgl/Layer.test.js index 60a5581990..4f8f1b17e4 100644 --- a/test/browser/spec/ol/renderer/webgl/Layer.test.js +++ b/test/browser/spec/ol/renderer/webgl/Layer.test.js @@ -1,7 +1,6 @@ import DataTileSource from '../../../../../../src/ol/source/DataTile.js'; import Layer from '../../../../../../src/ol/layer/Layer.js'; import Map from '../../../../../../src/ol/Map.js'; -import Projection from '../../../../../../src/ol/proj/Projection.js'; import TileLayer from '../../../../../../src/ol/layer/WebGLTile.js'; import VectorLayer from '../../../../../../src/ol/layer/Vector.js'; import VectorSource from '../../../../../../src/ol/source/Vector.js'; @@ -231,176 +230,4 @@ describe('ol/renderer/webgl/Layer', function () { dispose(map); }); }); - - describe('#getDataAtPixel (preserveDrawingBuffer false)', function () { - let map, target, source, layer, getContextOriginal; - beforeEach(function (done) { - getContextOriginal = HTMLCanvasElement.prototype.getContext; - HTMLCanvasElement.prototype.getContext = function (type, attributes) { - if (attributes && attributes.preserveDrawingBuffer) { - attributes.preserveDrawingBuffer = false; - } - return getContextOriginal.call(this, type, attributes); - }; - - const projection = new Projection({ - code: 'custom-image', - units: 'pixels', - extent: [0, 0, 200, 200], - }); - target = document.createElement('div'); - target.style.width = '100px'; - target.style.height = '100px'; - document.body.appendChild(target); - source = new DataTileSource({ - loader: function (z, x, y) { - return new Uint8Array(x == 0 ? [255, 0, 0, 255] : [0, 0, 0, 0]); - }, - projection: projection, - maxZoom: 0, - tileSize: 1, - maxResolution: 100, - }); - layer = new TileLayer({ - source: source, - extent: [50, 0, 150, 100], - }); - map = new Map({ - pixelRatio: 1, - target: target, - layers: [layer], - view: new View({ - projection: projection, - center: [100, 100], - zoom: 0, - }), - }); - map.once('rendercomplete', function () { - done(); - }); - }); - - afterEach(function () { - HTMLCanvasElement.prototype.getContext = getContextOriginal; - map.setLayers([]); - map.setTarget(null); - document.body.removeChild(target); - }); - - it('should not detect pixels outside of the layer extent', function () { - const pixel = [10, 10]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data).to.be(null); - }); - - it('should handle unreadable pixels in the layer extent', function () { - const pixel = [10, 60]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data.length).to.be(0); - }); - }); - - describe('#getDataAtPixel (preserveDrawingBuffer true)', function () { - let map, target, source, layer; - beforeEach(function (done) { - const projection = new Projection({ - code: 'custom-image', - units: 'pixels', - extent: [0, 0, 200, 200], - }); - target = document.createElement('div'); - target.style.width = '100px'; - target.style.height = '100px'; - document.body.appendChild(target); - source = new DataTileSource({ - loader: function (z, x, y) { - return new Uint8Array(x == 0 ? [255, 0, 0, 255] : [0, 0, 0, 0]); - }, - projection: projection, - maxZoom: 0, - tileSize: 1, - maxResolution: 100, - }); - layer = new TileLayer({ - source: source, - extent: [50, 0, 150, 100], - }); - map = new Map({ - pixelRatio: 1, - target: target, - layers: [layer], - view: new View({ - projection: projection, - center: [100, 100], - zoom: 0, - }), - }); - map.once('rendercomplete', function () { - done(); - }); - }); - - afterEach(function () { - map.setLayers([]); - map.setTarget(null); - document.body.removeChild(target); - }); - - it('should not detect pixels outside of the layer extent', function () { - const pixel = [10, 10]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data).to.be(null); - }); - - it('should detect pixels in the layer extent', function () { - const pixel = [10, 60]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data.length > 0).to.be(true); - expect(data[0]).to.be(255); - expect(data[1]).to.be(0); - expect(data[2]).to.be(0); - expect(data[3]).to.be(255); - }); - - it('should handle no data in the layer extent', function () { - const pixel = [60, 60]; - const frameState = map.frameState_; - const hitTolerance = 0; - const layerRenderer = layer.getRenderer(); - const data = layerRenderer.getDataAtPixel( - pixel, - frameState, - hitTolerance - ); - expect(data).to.be(null); - }); - }); });