From 3e2c04561736a1d3bb743e157edaf8a4df0a0ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Sun, 20 Jun 2021 22:35:21 +0200 Subject: [PATCH 1/2] Add test for hitdetection with wrap x --- .../ol/renderer/canvas/vectorlayer.test.js | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/test/browser/spec/ol/renderer/canvas/vectorlayer.test.js b/test/browser/spec/ol/renderer/canvas/vectorlayer.test.js index ab78a19d45..37a548cc9e 100644 --- a/test/browser/spec/ol/renderer/canvas/vectorlayer.test.js +++ b/test/browser/spec/ol/renderer/canvas/vectorlayer.test.js @@ -239,7 +239,12 @@ describe('ol.renderer.canvas.VectorLayer', function () { }); describe('#prepareFrame and #compose', function () { - let frameState, projExtent, renderer, worldWidth, buffer, loadExtents; + /** @type {import("../../../../../../src/ol/PluggableMap").FrameState*/ let frameState; + /** @type {import("../../../../../../src/ol/extent").Extent*/ let projExtent; + /** @type {CanvasVectorLayerRenderer} */ let renderer; + /** @type {number} */ let worldWidth; + /** @type {number} */ let buffer; + /** @type {Array*/ let loadExtents; function loader(extent) { loadExtents.push(extent); @@ -260,6 +265,7 @@ describe('ol.renderer.canvas.VectorLayer', function () { buffer = layer.getRenderBuffer(); loadExtents = []; frameState = { + pixelRatio: 1, viewHints: [], viewState: { projection: projection, @@ -412,9 +418,8 @@ describe('ol.renderer.canvas.VectorLayer', function () { }); frameState.layerStatesArray = [layer.getLayerState()]; frameState.layerIndex = 0; - frameState.extent = [-10000, -10000, 10000, 10000]; frameState.size = [100, 100]; - frameState.viewState.center = [0, 0]; + setExtent([-10000, -10000, 10000, 10000]); let rendered = false; if (renderer.prepareFrame(frameState)) { rendered = true; @@ -637,5 +642,61 @@ describe('ol.renderer.canvas.VectorLayer', function () { document.body.removeChild(target); }); + it('invalidates hitdetection image when map is moved horizontally', function (done) { + const layer = new VectorLayer({ + source: new VectorSource({ + wrapX: true, + }), + }); + const renderer = new CanvasVectorLayerRenderer(layer); + const projection = getProjection('EPSG:3857'); + const projExtent = projection.getExtent(); + const worldWidth = getWidth(projExtent); + /** @type {import("../../../../../../src/ol/PluggableMap").FrameState*/ + const frameState = { + viewHints: [], + pixelRatio: 1, + layerStatesArray: [layer.getLayerState()], + layerIndex: 0, + size: [100, 100], + viewState: { + projection: projection, + resolution: 1, + rotation: 0, + }, + }; + + function setExtent(extent) { + frameState.extent = extent; + frameState.viewState.center = getCenter(extent); + } + + layer.getSource().addFeature(new Feature(new Point([0, 0]))); + setExtent([-10000 - worldWidth, -10000, 10000 - worldWidth, 10000]); + if (renderer.prepareFrame(frameState)) { + renderer.renderFrame(frameState, null); + renderer.getFeatures([50, 50]).then((features) => { + const imageData = renderer.hitDetectionImageData_; + expect(imageData).to.be.an(ImageData); + expect(features).to.have.length(1); + + setExtent([ + 5e8 - worldWidth, + -10000, + 5e8 + 20000 - worldWidth, + 10000, + ]); + if (renderer.prepareFrame(frameState)) { + renderer.renderFrame(frameState); + renderer.getFeatures([50, 50]).then((features) => { + expect(renderer.hitDetectionImageData_).to.be.an(ImageData); + expect(renderer.hitDetectionImageData_ !== imageData).to.be(true); + expect(features).to.have.length(0); + done(); + }); + } + }); + } + }); }); }); From e8b336d11ee39c1603836a835a0a9a03b6b4d9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Sat, 19 Jun 2021 03:13:25 +0200 Subject: [PATCH 2/2] Fix hitdetection image invalidation --- src/ol/renderer/canvas/VectorLayer.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ol/renderer/canvas/VectorLayer.js b/src/ol/renderer/canvas/VectorLayer.js index 2f123e99df..c3aa878ac2 100644 --- a/src/ol/renderer/canvas/VectorLayer.js +++ b/src/ol/renderer/canvas/VectorLayer.js @@ -30,6 +30,7 @@ import { getSquaredTolerance as getSquaredRenderTolerance, renderFeature, } from '../vector.js'; +import {equals} from '../../array.js'; import { fromUserExtent, getTransformFromProjections, @@ -93,6 +94,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { */ this.renderedExtent_ = createEmpty(); + /** + * @private + * @type {import("../../extent.js").Extent} + */ + this.wrappedRenderedExtent_ = createEmpty(); + /** * @private * @type {number} @@ -323,7 +330,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { const resolution = this.renderedResolution_; const rotation = this.renderedRotation_; const projection = this.renderedProjection_; - const extent = this.renderedExtent_; + const extent = this.wrappedRenderedExtent_; const layer = this.getLayer(); const transforms = []; const width = size[0] * HIT_DETECT_RESOLUTION; @@ -548,6 +555,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { frameStateExtent, vectorLayerRenderBuffer * resolution ); + const renderedExtent = extent.slice(); const loadExtents = [extent.slice()]; const projectionExtent = projection.getExtent(); @@ -596,8 +604,13 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { this.renderedResolution_ == resolution && this.renderedRevision_ == vectorLayerRevision && this.renderedRenderOrder_ == vectorLayerRenderOrder && - containsExtent(this.renderedExtent_, extent) + containsExtent(this.wrappedRenderedExtent_, extent) ) { + if (!equals(this.renderedExtent_, renderedExtent)) { + this.hitDetectionImageData_ = null; + this.renderedExtent_ = renderedExtent; + } + this.renderedCenter_ = center; this.replayGroupChanged = false; return true; } @@ -702,7 +715,8 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer { this.renderedResolution_ = resolution; this.renderedRevision_ = vectorLayerRevision; this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; + this.renderedExtent_ = renderedExtent; + this.wrappedRenderedExtent_ = extent; this.renderedCenter_ = center; this.renderedProjection_ = projection; this.replayGroup_ = executorGroup;