Fix forEachLayerAtPixel for the canvas renderer

This commit is contained in:
Andreas Hocevar
2016-11-04 17:10:40 +01:00
parent ccdb955cd9
commit 2aa4f0c01c
11 changed files with 82 additions and 92 deletions

View File

@@ -70,7 +70,7 @@ ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = function(co
/** /**
* @param {ol.Pixel} pixel Pixel. * @param {ol.Coordinate} coordinate Coordinate.
* @param {olx.FrameState} frameState FrameState. * @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback. * callback.
@@ -78,7 +78,7 @@ ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = function(co
* @return {T|undefined} Callback result. * @return {T|undefined} Callback result.
* @template S,T,U * @template S,T,U
*/ */
ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) { ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {
if (!this.getImage()) { if (!this.getImage()) {
return undefined; return undefined;
} }
@@ -86,8 +86,6 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, fr
if (this.getLayer().getSource() instanceof ol.source.ImageVector) { if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
// for ImageVector sources use the original hit-detection logic, // for ImageVector sources use the original hit-detection logic,
// so that for example also transparent polygons are detected // so that for example also transparent polygons are detected
var coordinate = ol.transform.apply(
frameState.pixelToCoordinateTransform, pixel.slice());
var hasFeature = this.forEachFeatureAtCoordinate( var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, ol.functions.TRUE, this); coordinate, frameState, ol.functions.TRUE, this);
@@ -97,13 +95,8 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, fr
return undefined; return undefined;
} }
} else { } else {
// for all other image sources directly check the image var pixelOnCanvas = ol.transform.apply(
if (!this.imageTransformInv_) { this.coordinateToCanvasPixelTransform_, coordinate.slice());
this.imageTransformInv_ = ol.transform.invert(this.imageTransform_.slice());
}
var pixelOnCanvas =
this.getPixelOnCanvas(pixel, this.imageTransformInv_);
if (!this.hitCanvasContext_) { if (!this.hitCanvasContext_) {
this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
@@ -145,6 +138,7 @@ ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() {
ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, layerState) { ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, layerState) {
var pixelRatio = frameState.pixelRatio; var pixelRatio = frameState.pixelRatio;
var size = frameState.size;
var viewState = frameState.viewState; var viewState = frameState.viewState;
var viewCenter = viewState.center; var viewCenter = viewState.center;
var viewResolution = viewState.resolution; var viewResolution = viewState.resolution;
@@ -197,7 +191,11 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
ol.transform.translate(transform, ol.transform.translate(transform,
imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,
imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);
this.imageTransformInv_ = null; ol.transform.compose(ol.transform.reset(this.coordinateToCanvasPixelTransform_),
pixelRatio * size[0] / 2 - transform[4], pixelRatio * size[1] / 2 - transform[5],
pixelRatio / viewResolution, -pixelRatio / viewResolution,
0,
-viewCenter[0], -viewCenter[1]);
this.updateAttributions(frameState.attributions, image.getAttributions()); this.updateAttributions(frameState.attributions, image.getAttributions());
this.updateLogos(frameState, imageSource); this.updateLogos(frameState, imageSource);
} }

View File

@@ -2,6 +2,7 @@ goog.provide('ol.renderer.canvas.Layer');
goog.require('ol'); goog.require('ol');
goog.require('ol.extent'); goog.require('ol.extent');
goog.require('ol.functions');
goog.require('ol.render.Event'); goog.require('ol.render.Event');
goog.require('ol.render.canvas'); goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Immediate'); goog.require('ol.render.canvas.Immediate');
@@ -214,12 +215,21 @@ ol.renderer.canvas.Layer.prototype.prepareFrame = function(frameState, layerStat
/** /**
* @param {ol.Pixel} pixelOnMap Pixel. * @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.Transform} imageTransformInv The transformation matrix * @param {olx.FrameState} frameState Frame state.
* to convert from a map pixel to a canvas pixel. * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer callback.
* @return {ol.Pixel} The pixel. * @param {S} thisArg Value to use as `this` when executing `callback`.
* @protected * @return {T|undefined} Callback result.
* @template S,T
*/ */
ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = function(pixelOnMap, imageTransformInv) { ol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {
return ol.transform.apply(imageTransformInv, pixelOnMap.slice());
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, ol.functions.TRUE, this);
if (hasFeature) {
return callback.call(thisArg, this.getLayer(), null);
} else {
return undefined;
}
}; };

View File

@@ -200,3 +200,36 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
this.scheduleRemoveUnusedLayerRenderers(frameState); this.scheduleRemoveUnusedLayerRenderers(frameState);
this.scheduleExpireIconCache(frameState); this.scheduleExpireIconCache(frameState);
}; };
/**
* @inheritDoc
*/
ol.renderer.canvas.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
layerFilter, thisArg2) {
var result;
var viewState = frameState.viewState;
var viewResolution = viewState.resolution;
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var coordinate = ol.transform.apply(
frameState.pixelToCoordinateTransform, pixel.slice());
var i;
for (i = numLayers - 1; i >= 0; --i) {
var layerState = layerStates[i];
var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
layerFilter.call(thisArg2, layer)) {
var layerRenderer = /** @type {ol.renderer.canvas.Layer} */ (this.getLayerRenderer(layer));
result = layerRenderer.forEachLayerAtCoordinate(
coordinate, frameState, callback, thisArg);
if (result) {
return result;
}
}
}
return undefined;
};

View File

@@ -249,7 +249,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
/** /**
* @param {ol.Pixel} pixel Pixel. * @param {ol.Coordinate} coordinate Coordinate.
* @param {olx.FrameState} frameState FrameState. * @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback. * callback.
@@ -257,9 +257,8 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
* @return {T|undefined} Callback result. * @return {T|undefined} Callback result.
* @template S,T,U * @template S,T,U
*/ */
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function( ol.renderer.canvas.TileLayer.prototype.forEachLayerAtCoordinate = function(
pixel, frameState, callback, thisArg) { coordinate, frameState, callback, thisArg) {
var coordinate = ol.transform.apply(frameState.pixelToCoordinateTransform, pixel.slice());
var canvasPixel = ol.transform.apply(this.coordinateToCanvasPixelTransform_, coordinate); var canvasPixel = ol.transform.apply(this.coordinateToCanvasPixelTransform_, coordinate);
var imageData = this.context.getImageData(canvasPixel[0], canvasPixel[1], 1, 1).data; var imageData = this.context.getImageData(canvasPixel[0], canvasPixel[1], 1, 1).data;

View File

@@ -9,7 +9,6 @@ goog.require('ol.events');
goog.require('ol.events.EventType'); goog.require('ol.events.EventType');
goog.require('ol.functions'); goog.require('ol.functions');
goog.require('ol.source.State'); goog.require('ol.source.State');
goog.require('ol.transform');
/** /**
@@ -45,29 +44,6 @@ ol.inherits(ol.renderer.Layer, ol.Observable);
ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction; ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction;
/**
* @param {ol.Pixel} pixel Pixel.
* @param {olx.FrameState} frameState Frame state.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T
*/
ol.renderer.Layer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
var coordinate = ol.transform.apply(
frameState.pixelToCoordinateTransform, pixel.slice());
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, ol.functions.TRUE, this);
if (hasFeature) {
return callback.call(thisArg, this.layer_, null);
} else {
return undefined;
}
};
/** /**
* @param {ol.Coordinate} coordinate Coordinate. * @param {ol.Coordinate} coordinate Coordinate.
* @param {olx.FrameState} frameState Frame state. * @param {olx.FrameState} frameState Frame state.

View File

@@ -167,6 +167,7 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, fram
/** /**
* @abstract
* @param {ol.Pixel} pixel Pixel. * @param {ol.Pixel} pixel Pixel.
* @param {olx.FrameState} frameState FrameState. * @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
@@ -181,29 +182,7 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, fram
* @template S,T,U * @template S,T,U
*/ */
ol.renderer.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg, ol.renderer.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
layerFilter, thisArg2) { layerFilter, thisArg2) {};
var result;
var viewState = frameState.viewState;
var viewResolution = viewState.resolution;
var layerStates = frameState.layerStatesArray;
var numLayers = layerStates.length;
var i;
for (i = numLayers - 1; i >= 0; --i) {
var layerState = layerStates[i];
var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
layerFilter.call(thisArg2, layer)) {
var layerRenderer = this.getLayerRenderer(layer);
result = layerRenderer.forEachLayerAtPixel(
pixel, frameState, callback, thisArg);
if (result) {
return result;
}
}
}
return undefined;
};
/** /**

View File

@@ -219,13 +219,7 @@ ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = function(coordin
/** /**
* @param {ol.Pixel} pixel Pixel. * @inheritDoc
* @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T,U
*/ */
ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) { ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
if (!this.image_ || !this.image_.getImage()) { if (!this.image_ || !this.image_.getImage()) {

View File

@@ -251,3 +251,16 @@ ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() {
* @return {boolean} whether composeFrame should be called. * @return {boolean} whether composeFrame should be called.
*/ */
ol.renderer.webgl.Layer.prototype.prepareFrame = function(frameState, layerState, context) {}; ol.renderer.webgl.Layer.prototype.prepareFrame = function(frameState, layerState, context) {};
/**
* @abstract
* @param {ol.Pixel} pixel Pixel.
* @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T,U
*/
ol.renderer.webgl.Layer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {};

View File

@@ -584,7 +584,7 @@ ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = function(pixel, frameState
var layer = layerState.layer; var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
layerFilter.call(thisArg, layer)) { layerFilter.call(thisArg, layer)) {
var layerRenderer = this.getLayerRenderer(layer); var layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layer));
result = layerRenderer.forEachLayerAtPixel( result = layerRenderer.forEachLayerAtPixel(
pixel, frameState, callback, thisArg); pixel, frameState, callback, thisArg);
if (result) { if (result) {

View File

@@ -358,13 +358,7 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerS
/** /**
* @param {ol.Pixel} pixel Pixel. * @inheritDoc
* @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T,U
*/ */
ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) { ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
if (!this.framebuffer) { if (!this.framebuffer) {

View File

@@ -154,13 +154,7 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = function(coordi
/** /**
* @param {ol.Pixel} pixel Pixel. * @inheritDoc
* @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T,U
*/ */
ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) { ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
var coordinate = ol.transform.apply( var coordinate = ol.transform.apply(