diff --git a/src/ol/renderer/canvas/Layer.js b/src/ol/renderer/canvas/Layer.js index 346e4b853e..d349baea1c 100644 --- a/src/ol/renderer/canvas/Layer.js +++ b/src/ol/renderer/canvas/Layer.js @@ -9,13 +9,14 @@ import { compose as composeTransform, create as createTransform, } from '../../transform.js'; -import {createCanvasContext2D} from '../../dom.js'; import { + containsCoordinate, getBottomLeft, getBottomRight, getTopLeft, getTopRight, } from '../../extent.js'; +import {createCanvasContext2D} from '../../dom.js'; import {rotateAtOffset} from '../../render/canvas.js'; /** @@ -284,6 +285,20 @@ class CanvasLayerRenderer extends LayerRenderer { ); 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; + } + } + let data; try { const x = Math.round(renderPixel[0]); diff --git a/test/spec/ol/renderer/canvas/imagelayer.test.js b/test/spec/ol/renderer/canvas/imagelayer.test.js index fb340a8418..0ef505725a 100644 --- a/test/spec/ol/renderer/canvas/imagelayer.test.js +++ b/test/spec/ol/renderer/canvas/imagelayer.test.js @@ -66,6 +66,189 @@ describe('ol.renderer.canvas.ImageLayer', function () { }); }); + describe('#forEachLayerAtPixel Image CORS', function () { + let map, + target, + imageExtent, + projection, + sourceCross, + source, + imageLayer, + imageLayerCross; + beforeEach(function (done) { + 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); + imageExtent = [0, 0, 20, 20]; + source = new Static({ + url: `https://openlayers.org/assets/theme/img/logo70.png`, + projection: projection, + imageExtent: imageExtent, + }); + imageLayer = new ImageLayer({ + source: source, + }); + sourceCross = new Static({ + url: `https://openlayers.org/assets/theme/img/logo70.png`, + projection: projection, + imageExtent: imageExtent, + crossOrigin: 'anonymous', + }); + imageLayerCross = new ImageLayer({ + source: sourceCross, + }); + map = new Map({ + pixelRatio: 1, + target: target, + layers: [imageLayer, imageLayerCross], + view: new View({ + projection: projection, + center: [10, 10], + zoom: 1, + maxZoom: 8, + }), + }); + let loadedCount = 0; + [source, sourceCross].forEach(function (source) { + source.once('imageloadend', function () { + loadedCount++; + if (loadedCount === 2) { + done(); + } + }); + }); + }); + + afterEach(function () { + map.setTarget(null); + document.body.removeChild(target); + }); + + it('should detect pixels even if there is no color because neither crossOrigin or extent is 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); + }); + + 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); + }); + + it('should not detect pixels outside of the layer extent with extent set', function () { + imageLayerCross.setVisible(true); + 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); + }); + }); + describe('Image rendering', function () { let map, div, layer;