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 {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
@@ -78,7 +78,7 @@ ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = function(co
* @return {T|undefined} Callback result.
* @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()) {
return undefined;
}
@@ -86,8 +86,6 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, fr
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 coordinate = ol.transform.apply(
frameState.pixelToCoordinateTransform, pixel.slice());
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, ol.functions.TRUE, this);
@@ -97,13 +95,8 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, fr
return undefined;
}
} else {
// for all other image sources directly check the image
if (!this.imageTransformInv_) {
this.imageTransformInv_ = ol.transform.invert(this.imageTransform_.slice());
}
var pixelOnCanvas =
this.getPixelOnCanvas(pixel, this.imageTransformInv_);
var pixelOnCanvas = ol.transform.apply(
this.coordinateToCanvasPixelTransform_, coordinate.slice());
if (!this.hitCanvasContext_) {
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) {
var pixelRatio = frameState.pixelRatio;
var size = frameState.size;
var viewState = frameState.viewState;
var viewCenter = viewState.center;
var viewResolution = viewState.resolution;
@@ -197,7 +191,11 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
ol.transform.translate(transform,
imagePixelRatio * (imageExtent[0] - viewCenter[0]) / 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.updateLogos(frameState, imageSource);
}

View File

@@ -2,6 +2,7 @@ goog.provide('ol.renderer.canvas.Layer');
goog.require('ol');
goog.require('ol.extent');
goog.require('ol.functions');
goog.require('ol.render.Event');
goog.require('ol.render.canvas');
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.Transform} imageTransformInv The transformation matrix
* to convert from a map pixel to a canvas pixel.
* @return {ol.Pixel} The pixel.
* @protected
* @param {ol.Coordinate} coordinate Coordinate.
* @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.canvas.Layer.prototype.getPixelOnCanvas = function(pixelOnMap, imageTransformInv) {
return ol.transform.apply(imageTransformInv, pixelOnMap.slice());
ol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {
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.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 {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
@@ -257,9 +257,8 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
* @return {T|undefined} Callback result.
* @template S,T,U
*/
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
pixel, frameState, callback, thisArg) {
var coordinate = ol.transform.apply(frameState.pixelToCoordinateTransform, pixel.slice());
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtCoordinate = function(
coordinate, frameState, callback, thisArg) {
var canvasPixel = ol.transform.apply(this.coordinateToCanvasPixelTransform_, coordinate);
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.functions');
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;
/**
* @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 {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 {olx.FrameState} frameState FrameState.
* @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
*/
ol.renderer.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 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;
};
layerFilter, thisArg2) {};
/**

View File

@@ -219,13 +219,7 @@ ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = function(coordin
/**
* @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
* @inheritDoc
*/
ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
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.
*/
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;
if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
layerFilter.call(thisArg, layer)) {
var layerRenderer = this.getLayerRenderer(layer);
var layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layer));
result = layerRenderer.forEachLayerAtPixel(
pixel, frameState, callback, thisArg);
if (result) {

View File

@@ -358,13 +358,7 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerS
/**
* @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
* @inheritDoc
*/
ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
if (!this.framebuffer) {

View File

@@ -154,13 +154,7 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = function(coordi
/**
* @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
* @inheritDoc
*/
ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
var coordinate = ol.transform.apply(