Remove deprecated method PluggableMap#forEachLayerAtPixel

This commit is contained in:
Maximilian Krög
2022-07-24 21:39:34 +02:00
parent 0f8de89318
commit 2897f03ea5
12 changed files with 39 additions and 634 deletions

View File

@@ -6,7 +6,7 @@ docs: >
Example of data resampling when using raster DEM (digital elevation model) data. Example of data resampling when using raster DEM (digital elevation model) data.
The <code>interpolate: false</code> setting is used to disable interpolation of data values during The <code>interpolate: false</code> setting is used to disable interpolation of data values during
reprojection and rendering. Elevation data is reprojection and rendering. Elevation data is
calculated from the pixel value returned by <b>forEachLayerAtPixel</b>. For comparison a second map calculated from the pixel value returned by <b>getData</b>. For comparison a second map reprojected
with interpolation enabled returns inaccurate elevations which are very noticeable close to 3107 meters with interpolation enabled returns inaccurate elevations which are very noticeable close to 3107 meters
due to how elevation is calculated from the pixel value. due to how elevation is calculated from the pixel value.
tags: "disable image interpolation, xyz, maptiler, reprojection" tags: "disable image interpolation, xyz, maptiler, reprojection"
@@ -21,7 +21,7 @@ cloak:
<div> <div>
<label> <label>
Elevation Elevation
<span id="info1">0.0</span> meters <span id="info1">-</span> meters
</label> </label>
</div> </div>
</div> </div>
@@ -31,7 +31,7 @@ cloak:
<div> <div>
<label> <label>
Elevation Elevation
<span id="info2">0.0</span> meters <span id="info2">-</span> meters
</label> </label>
</div> </div>
</div> </div>

View File

@@ -9,8 +9,6 @@ const attributions =
'<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'; '<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>';
const notInterpolated = new TileLayer({ const notInterpolated = new TileLayer({
// specify className so forEachLayerAtPixel can distinguish layers
className: 'ol-layer-dem',
source: new XYZ({ source: new XYZ({
attributions: attributions, attributions: attributions,
url: url:
@@ -51,39 +49,25 @@ const map2 = new Map({
view: view, view: view,
}); });
function getHeight(rgba) {
return -10000 + (rgba[0] * 256 * 256 + rgba[1] * 256 + rgba[2]) * 0.1;
}
const info1 = document.getElementById('info1'); const info1 = document.getElementById('info1');
const info2 = document.getElementById('info2'); const info2 = document.getElementById('info2');
const showElevations = function (evt) { const showElevations = function (evt) {
if (evt.dragging) { if (evt.dragging) {
return; return;
} }
map1.forEachLayerAtPixel( const notInterpolatedPixel = notInterpolated.getData(evt.pixel);
evt.pixel, info1.innerText = notInterpolatedPixel
function (layer, pixel) { ? getHeight(notInterpolatedPixel).toFixed(1)
const height = : '-';
-10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1;
info1.innerText = height.toFixed(1); const interpolatedPixel = interpolated.getData(evt.pixel);
}, info2.innerText = interpolatedPixel
{ ? getHeight(interpolatedPixel).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;
},
}
);
}; };
map1.on('pointermove', showElevations); map1.on('pointermove', showElevations);

View File

@@ -693,51 +693,6 @@ class PluggableMap extends BaseObject {
return layers; 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 * Detect if features intersect a pixel on the viewport. Layers included in the
* detection can be configured through `opt_layerFilter`. * detection can be configured through `opt_layerFilter`.

View File

@@ -83,11 +83,6 @@ import {listen, unlistenByKey} from '../events.js';
* *
* A generic `change` event is fired when the state of the source changes. * 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#prerender
* @fires import("../render/Event.js").RenderEvent#postrender * @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 * 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 * not manage this layer in its layers collection. This
* {@link module:ol/Map~Map#forEachLayerAtPixel} will receive `null` as layer. This
* is useful for temporary layers. To remove an unmanaged layer from the map, * is useful for temporary layers. To remove an unmanaged layer from the map,
* use `#setMap(null)`. * use `#setMap(null)`.
* *

View File

@@ -149,50 +149,6 @@ class CompositeMapRenderer extends MapRenderer {
this.scheduleExpireIconCache(frameState); 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<import("../source/Source").default>, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {function(import("../layer/Layer.js").default<import("../source/Source").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; export default CompositeMapRenderer;

View File

@@ -133,19 +133,6 @@ class LayerRenderer extends Observable {
return undefined; 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. * @return {LayerType} Layer.
*/ */

View File

@@ -170,24 +170,6 @@ class MapRenderer extends Disposable {
return result; 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<import("../source/Source").default>, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {function(import("../layer/Layer.js").default<import("../source/Source").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("../coordinate.js").Coordinate} coordinate Coordinate.
* @param {import("../PluggableMap.js").FrameState} frameState FrameState. * @param {import("../PluggableMap.js").FrameState} frameState FrameState.

View File

@@ -10,15 +10,14 @@ import {
create as createTransform, create as createTransform,
} from '../../transform.js'; } from '../../transform.js';
import {asArray} from '../../color.js'; import {asArray} from '../../color.js';
import {createCanvasContext2D} from '../../dom.js';
import {equals} from '../../array.js';
import { import {
containsCoordinate,
getBottomLeft, getBottomLeft,
getBottomRight, getBottomRight,
getTopLeft, getTopLeft,
getTopRight, getTopRight,
} from '../../extent.js'; } from '../../extent.js';
import {createCanvasContext2D} from '../../dom.js';
import {equals} from '../../array.js';
/** /**
* @type {Array<HTMLCanvasElement>} * @type {Array<HTMLCanvasElement>}
@@ -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. * Clean up.
*/ */

View File

@@ -7,11 +7,9 @@ import RenderEvent from '../../render/Event.js';
import RenderEventType from '../../render/EventType.js'; import RenderEventType from '../../render/EventType.js';
import WebGLHelper from '../../webgl/Helper.js'; import WebGLHelper from '../../webgl/Helper.js';
import { import {
apply as applyTransform,
compose as composeTransform, compose as composeTransform,
create as createTransform, create as createTransform,
} from '../../transform.js'; } from '../../transform.js';
import {containsCoordinate} from '../../extent.js';
/** /**
* @typedef {Object} PostProcessesOptions * @typedef {Object} PostProcessesOptions
@@ -259,68 +257,6 @@ class WebGLLayerRenderer extends LayerRenderer {
postRender(context, frameState) { postRender(context, frameState) {
this.dispatchRenderEvent_(RenderEventType.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; export default WebGLLayerRenderer;

View File

@@ -19,7 +19,6 @@ import PinchZoom from '../../../../src/ol/interaction/PinchZoom.js';
import Property from '../../../../src/ol/layer/Property.js'; import Property from '../../../../src/ol/layer/Property.js';
import Select from '../../../../src/ol/interaction/Select.js'; import Select from '../../../../src/ol/interaction/Select.js';
import TileLayer from '../../../../src/ol/layer/Tile.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 VectorLayer from '../../../../src/ol/layer/Vector.js';
import VectorSource from '../../../../src/ol/source/Vector.js'; import VectorSource from '../../../../src/ol/source/Vector.js';
import VectorTileLayer from '../../../../src/ol/layer/VectorTile.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 () { describe('#render()', function () {
let target, map; let target, map;

View File

@@ -13,8 +13,10 @@ import View from '../../../../../../src/ol/View.js';
import {get as getProj} from '../../../../../../src/ol/proj.js'; import {get as getProj} from '../../../../../../src/ol/proj.js';
describe('ol/renderer/canvas/ImageLayer', function () { describe('ol/renderer/canvas/ImageLayer', function () {
describe('#forEachLayerAtCoordinate', function () { describe('#getData', function () {
let map, target, source; let map, target, source;
/** @type {ImageLayer} */
let layer;
beforeEach(function (done) { beforeEach(function (done) {
const projection = new Projection({ const projection = new Projection({
code: 'custom-image', code: 'custom-image',
@@ -30,14 +32,13 @@ describe('ol/renderer/canvas/ImageLayer', function () {
projection: projection, projection: projection,
imageExtent: [0, 0, 20, 20], imageExtent: [0, 0, 20, 20],
}); });
layer = new ImageLayer({
source: source,
});
map = new Map({ map = new Map({
pixelRatio: 1, pixelRatio: 1,
target: target, target: target,
layers: [ layers: [layer],
new ImageLayer({
source: source,
}),
],
view: new View({ view: new View({
projection: projection, projection: projection,
center: [10, 10], center: [10, 10],
@@ -57,19 +58,13 @@ describe('ol/renderer/canvas/ImageLayer', function () {
it('properly detects pixels', function () { it('properly detects pixels', function () {
map.renderSync(); map.renderSync();
let has = false;
function hasLayer() { expect(layer.getData([20, 80])[3]).to.not.be(0);
has = true; expect(layer.getData([10, 90])[3]).to.be(0);
}
map.forEachLayerAtPixel([20, 80], hasLayer);
expect(has).to.be(true);
has = false;
map.forEachLayerAtPixel([10, 90], hasLayer);
expect(has).to.be(false);
}); });
}); });
describe('#forEachLayerAtPixel Image CORS', function () { describe('#getData Image CORS', function () {
let map, let map,
target, target,
imageExtent, imageExtent,
@@ -133,34 +128,22 @@ describe('ol/renderer/canvas/ImageLayer', function () {
document.body.removeChild(target); 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); imageLayerCross.setVisible(false);
imageLayer.setVisible(true); imageLayer.setVisible(true);
map.renderSync(); map.renderSync();
let has = false;
function hasLayer() { expect(imageLayer.getData([50, 50])).to.be(null);
has = true; expect(imageLayer.getData([10, 10])).to.be(null);
}
map.forEachLayerAtPixel([50, 50], hasLayer);
expect(has).to.be(true);
has = false;
map.forEachLayerAtPixel([10, 10], hasLayer);
expect(has).to.be(true);
}); });
it('should not detect pixels outside of the layer extent with crossOrigin set', function () { it('should not detect pixels outside of the layer extent with crossOrigin set', function () {
imageLayerCross.setVisible(true); imageLayerCross.setVisible(true);
imageLayer.setVisible(false); imageLayer.setVisible(false);
map.renderSync(); map.renderSync();
let has = false;
function hasLayer() { expect(imageLayerCross.getData([50, 50])).to.not.be(null);
has = true; expect(imageLayerCross.getData([10, 10])).to.be(null);
}
map.forEachLayerAtPixel([50, 50], hasLayer);
expect(has).to.be(true);
has = false;
map.forEachLayerAtPixel([10, 10], hasLayer);
expect(has).to.be(false);
}); });
it('should not detect pixels outside of the layer extent with extent set', function () { 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); imageLayerCross.setExtent(imageExtent);
imageLayer.setVisible(false); imageLayer.setVisible(false);
map.renderSync(); 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 () { expect(imageLayerCross.getData([50, 50])).to.not.be(null);
let map, target, source, imageLayer; expect(imageLayerCross.getData([10, 10])).to.be(null);
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);
}); });
}); });

View File

@@ -1,7 +1,6 @@
import DataTileSource from '../../../../../../src/ol/source/DataTile.js'; import DataTileSource from '../../../../../../src/ol/source/DataTile.js';
import Layer from '../../../../../../src/ol/layer/Layer.js'; import Layer from '../../../../../../src/ol/layer/Layer.js';
import Map from '../../../../../../src/ol/Map.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 TileLayer from '../../../../../../src/ol/layer/WebGLTile.js';
import VectorLayer from '../../../../../../src/ol/layer/Vector.js'; import VectorLayer from '../../../../../../src/ol/layer/Vector.js';
import VectorSource from '../../../../../../src/ol/source/Vector.js'; import VectorSource from '../../../../../../src/ol/source/Vector.js';
@@ -231,176 +230,4 @@ describe('ol/renderer/webgl/Layer', function () {
dispose(map); 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);
});
});
}); });