From b4cb786f2901add9438ad60ee7be13a38fd504bf Mon Sep 17 00:00:00 2001 From: tsauerwein Date: Fri, 23 Jan 2015 16:50:42 +0100 Subject: [PATCH] Implement forEachLayerAtPixel for canvas --- .../canvas/canvasimagelayerrenderer.js | 63 +++++++++++++++++++ src/ol/renderer/canvas/canvaslayerrenderer.js | 16 +++++ .../canvas/canvastilelayerrenderer.js | 35 +++++++++++ 3 files changed, 114 insertions(+) diff --git a/src/ol/renderer/canvas/canvasimagelayerrenderer.js b/src/ol/renderer/canvas/canvasimagelayerrenderer.js index 834f0e771f..abc974a832 100644 --- a/src/ol/renderer/canvas/canvasimagelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasimagelayerrenderer.js @@ -4,11 +4,13 @@ goog.require('goog.asserts'); goog.require('goog.vec.Mat4'); goog.require('ol.ImageBase'); goog.require('ol.ViewHint'); +goog.require('ol.dom'); goog.require('ol.extent'); goog.require('ol.layer.Image'); goog.require('ol.proj'); goog.require('ol.renderer.Map'); goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.source.ImageVector'); goog.require('ol.vec.Mat4'); @@ -35,6 +37,18 @@ ol.renderer.canvas.ImageLayer = function(mapRenderer, imageLayer) { */ this.imageTransform_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {?goog.vec.Mat4.Number} + */ + this.imageTransformInv_ = null; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.hitCanvasContext_ = null; + }; goog.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.Layer); @@ -61,6 +75,54 @@ ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtPixel = }; +/** + * @inheritDoc + */ +ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = + function(coordinate, frameState, callback, thisArg) { + if (goog.isNull(this.getImage())) { + return undefined; + } + + if (this.getLayer().getSource() instanceof ol.source.ImageVector) { + // for ImageVector sources use the original hit-detection logic, + // so that for example also transparent polygons are detected + var hasFeature = this.forEachFeatureAtPixel( + coordinate, frameState, goog.functions.TRUE, this); + + if (hasFeature) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } + } else { + // for all other image sources directly check the image + if (goog.isNull(this.imageTransformInv_)) { + this.imageTransformInv_ = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); + } + + var pixelOnCanvas = + this.getPixelFromCoordinates(coordinate, this.imageTransformInv_); + + if (goog.isNull(this.hitCanvasContext_)) { + this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); + } + + this.hitCanvasContext_.clearRect(0, 0, 1, 1); + this.hitCanvasContext_.drawImage( + this.getImage(), pixelOnCanvas[0], pixelOnCanvas[1], 1, 1, 0, 0, 1, 1); + + var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } + } +}; + + /** * @inheritDoc */ @@ -135,6 +197,7 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = viewRotation, imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); + this.imageTransformInv_ = null; this.updateAttributions(frameState.attributions, image.getAttributions()); this.updateLogos(frameState, imageSource); } diff --git a/src/ol/renderer/canvas/canvaslayerrenderer.js b/src/ol/renderer/canvas/canvaslayerrenderer.js index a9a699d8b2..90712130af 100644 --- a/src/ol/renderer/canvas/canvaslayerrenderer.js +++ b/src/ol/renderer/canvas/canvaslayerrenderer.js @@ -216,6 +216,22 @@ ol.renderer.canvas.Layer.prototype.getTransform = function(frameState) { ol.renderer.canvas.Layer.prototype.prepareFrame = goog.abstractMethod; +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {goog.vec.Mat4.Number} imageTransformInv The transformation matrix + * to convert from a map pixel to a canvas pixel. + * @return {ol.Pixel} + * @protected + */ +ol.renderer.canvas.Layer.prototype.getPixelFromCoordinates = + function(coordinate, imageTransformInv) { + var pixelOnMap = this.getMap().getPixelFromCoordinate(coordinate); + var pixelOnCanvas = [0, 0]; + ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas); + return pixelOnCanvas; +}; + + /** * @param {ol.Size} size Size. * @return {boolean} True when the canvas with the current size does not exceed diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index b4549b1ad8..cb7859a0d8 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -60,6 +60,12 @@ ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) { */ this.imageTransform_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {?goog.vec.Mat4.Number} + */ + this.imageTransformInv_ = null; + /** * @private * @type {number} @@ -408,6 +414,35 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = viewState.rotation, (origin[0] - center[0]) / tilePixelResolution, (center[1] - origin[1]) / tilePixelResolution); + this.imageTransformInv_ = null; return true; }; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = + function(coordinate, frameState, callback, thisArg) { + if (goog.isNull(this.context_)) { + return undefined; + } + + if (goog.isNull(this.imageTransformInv_)) { + this.imageTransformInv_ = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); + } + + var pixelOnCanvas = + this.getPixelFromCoordinates(coordinate, this.imageTransformInv_); + + var imageData = this.context_.getImageData( + pixelOnCanvas[0], pixelOnCanvas[1], 1, 1).data; + + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } +};