diff --git a/examples/image-vector-layer.js b/examples/image-vector-layer.js index 0a9ef82870..cd24c917b4 100644 --- a/examples/image-vector-layer.js +++ b/examples/image-vector-layer.js @@ -56,35 +56,32 @@ const featureOverlay = new VectorLayer({ let highlight; const displayFeatureInfo = function(pixel) { - const feature = map.forEachFeatureAtPixel(pixel, function(feature) { - return feature; - }); + map.getLayers().item(0).getFeatures(pixel).then(function(features) { + const feature = features.length > 0 ? features[0] : undefined; - const info = document.getElementById('info'); - if (feature) { - info.innerHTML = feature.getId() + ': ' + feature.get('name'); - } else { - info.innerHTML = ' '; - } - - if (feature !== highlight) { - if (highlight) { - featureOverlay.getSource().removeFeature(highlight); - } + const info = document.getElementById('info'); if (feature) { - featureOverlay.getSource().addFeature(feature); + info.innerHTML = feature.getId() + ': ' + feature.get('name'); + } else { + info.innerHTML = ' '; } - highlight = feature; - } + if (feature !== highlight) { + if (highlight) { + featureOverlay.getSource().removeFeature(highlight); + } + if (feature) { + featureOverlay.getSource().addFeature(feature); + } + highlight = feature; + } + }); }; map.on('pointermove', function(evt) { - if (evt.dragging) { - return; + if (!evt.dragging) { + displayFeatureInfo(evt.pixel); } - const pixel = map.getEventPixel(evt.originalEvent); - displayFeatureInfo(pixel); }); map.on('click', function(evt) { diff --git a/src/ol/renderer/canvas/VectorImageLayer.js b/src/ol/renderer/canvas/VectorImageLayer.js index e1cec57020..85b4efd2f8 100644 --- a/src/ol/renderer/canvas/VectorImageLayer.js +++ b/src/ol/renderer/canvas/VectorImageLayer.js @@ -10,6 +10,7 @@ import CanvasVectorLayerRenderer from './VectorLayer.js'; import EventType from '../../events/EventType.js'; import ImageState from '../../ImageState.js'; import {renderDeclutterItems} from '../../render.js'; +import {apply, compose, create} from '../../transform.js'; /** * @classdesc @@ -36,6 +37,18 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { */ this.layerImageRatio_ = layer.getImageRatio(); + /** + * @private + * @type {import("../../transform.js").Transform}; + */ + this.coordinateToVectorPixelTransform_ = create(); + + /** + * @private + * @type {import("../../transform.js").Transform}; + */ + this.renderedPixelToCoordinateTransform_ = null; + } /** @@ -46,6 +59,22 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { super.disposeInternal(); } + /** + * @inheritDoc + */ + getFeatures(pixel) { + if (this.vectorRenderer_) { + const vectorPixel = apply(this.coordinateToVectorPixelTransform_, + apply(this.renderedPixelToCoordinateTransform_, pixel.slice())); + return this.vectorRenderer_.getFeatures(vectorPixel); + } else { + const promise = new Promise(function(resolve, reject) { + resolve([]); + }); + return promise; + } + } + /** * @inheritDoc */ @@ -68,16 +97,15 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { renderedExtent = renderedExtent.slice(0); scaleFromCenter(renderedExtent, this.layerImageRatio_); } + const width = getWidth(renderedExtent) / viewResolution; + const height = getHeight(renderedExtent) / viewResolution; if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) { vectorRenderer.useContainer(null, null, 1); const context = vectorRenderer.context; const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, { declutterItems: [], - size: [ - getWidth(renderedExtent) / viewResolution, - getHeight(renderedExtent) / viewResolution - ], + size: [width, height], viewState: /** @type {import("../../View.js").State} */ (assign({}, frameState.viewState, { rotation: 0 })) @@ -102,7 +130,14 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer { const image = this.image_; const imageResolution = image.getResolution(); const imagePixelRatio = image.getPixelRatio(); - this.renderedResolution = imageResolution * pixelRatio / imagePixelRatio; + const renderedResolution = imageResolution * pixelRatio / imagePixelRatio; + this.renderedResolution = renderedResolution; + this.renderedPixelToCoordinateTransform_ = frameState.pixelToCoordinateTransform.slice(); + this.coordinateToVectorPixelTransform_ = compose(this.coordinateToVectorPixelTransform_, + width / 2, height / 2, + 1 / renderedResolution, -1 / renderedResolution, + 0, + -viewState.center[0], -viewState.center[1]); } return !!this.image_; diff --git a/test/spec/ol/layer/vectorimage.test.js b/test/spec/ol/layer/vectorimage.test.js new file mode 100644 index 0000000000..f847b9423e --- /dev/null +++ b/test/spec/ol/layer/vectorimage.test.js @@ -0,0 +1,61 @@ +import Feature from '../../../../src/ol/Feature.js'; +import Point from '../../../../src/ol/geom/Point.js'; +import Map from '../../../../src/ol/Map.js'; +import View from '../../../../src/ol/View.js'; +import VectorImageLayer from '../../../../src/ol/layer/VectorImage.js'; +import VectorSource from '../../../../src/ol/source/Vector.js'; + +describe('ol/layer/VectorImage', function() { + + describe('#getFeatures()', function() { + + let map, layer; + + beforeEach(function() { + layer = new VectorImageLayer({ + source: new VectorSource({ + features: [ + new Feature({ + geometry: new Point([-1000000, 0]), + name: 'feature1' + }), + new Feature({ + geometry: new Point([1000000, 0]), + name: 'feture2' + }) + ] + }) + }); + const container = document.createElement('div'); + container.style.width = '256px'; + container.style.height = '256px'; + document.body.appendChild(container); + map = new Map({ + target: container, + layers: [ + layer + ], + view: new View({ + zoom: 2, + center: [0, 0] + }) + }); + }); + + afterEach(function() { + document.body.removeChild(map.getTargetElement()); + map.setTarget(null); + }); + + it('detects features properly', function(done) { + map.renderSync(); + const pixel = map.getPixelFromCoordinate([-1000000, 0]); + layer.getFeatures(pixel).then(function(features) { + expect(features[0].get('name')).to.be('feature1'); + done(); + }); + }); + + }); + +}); diff --git a/test/spec/ol/renderer/canvas/vectorimage.test.js b/test/spec/ol/renderer/canvas/vectorimage.test.js index 98d41e1fda..ab261f1e6b 100644 --- a/test/spec/ol/renderer/canvas/vectorimage.test.js +++ b/test/spec/ol/renderer/canvas/vectorimage.test.js @@ -3,6 +3,7 @@ import VectorSource from '../../../../../src/ol/source/Vector.js'; import CanvasVectorImageLayerRenderer from '../../../../../src/ol/renderer/canvas/VectorImageLayer.js'; import {get as getProjection} from '../../../../../src/ol/proj.js'; import {scaleFromCenter} from '../../../../../src/ol/extent.js'; +import {create} from '../../../../../src/ol/transform.js'; describe('ol/renderer/canvas/VectorImageLayer', function() { @@ -39,6 +40,7 @@ describe('ol/renderer/canvas/VectorImageLayer', function() { layerIndex: 0, extent: extent, viewHints: [], + pixelToCoordinateTransform: create(), viewState: { center: [0, 0], projection: projection,