-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Introduce hasFeatureAtPixel #3066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce hasFeatureAtPixel #3066
Conversation
ol.renderer.Map.prototype.hasFeatureAtPixel = | ||
function(coordinate, frameState, layerFilter, thisArg) { | ||
var hasFeature = this.forEachFeatureAtPixel( | ||
coordinate, frameState, goog.functions.TRUE, this, layerFilter, thisArg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused why this wouldn't call hasFeatureAtPixel
for each layer renderer (with a visible layer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused why this wouldn't call hasFeatureAtPixel for each layer renderer (with a visible layer).
Am I not doing exactly that by calling forEachFeatureAtPixel
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused why this wouldn't call hasFeatureAtPixel for each layer renderer (with a visible layer).
This one is the default implementation, used by the Canvas and DOM renderers. It is based on the forEachFeatureAtPixel
function.
The WebGL implementation does call hasFeatuteAtPixel
for each layer renderer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was expecting to see something like this at the map renderer level:
ol.renderer.Map.prototype.hasFeatureAtPixel =
function(coordinate, frameState, layerFilter, thisArg) {
var layerStates = this.getMap().getLayerGroup().getLayerStatesArray();
for (var i = layerStates.length - 1; i >= 0; --i) {
var layerState = layerStates[i];
var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
layerFilter.call(thisArg, layer) &&
this.getLayerRenderer(layer).hasFeatureAtPixel(coordinate, frameState)) {
return true;
}
}
return false;
};
And then see the default layer renderer implementation of hasFeatureAtPixel
delegate to forEachFeatureAtPixel
.
But I see now that this doesn't account for feature overlays and the specific work that the WebGL renderer has to do there. This can happen later, but I still can imagine that we could have one hasFeatureAtPixel
implementation at the map renderer level that could call a specific overlayHasFeatureAtPixel
method for each map renderer type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see. I think this would make sense if there was a layer renderer which had an optimized implementation for hasFeatureAtPixel
. As this is currently not the case, I would prefer to stick with the solution of simply falling back to forEachFeatureAtPixel
of the map renderer.
I like the idea of |
In fact, the |
Good point! |
var hasFeature = this.forEachFeatureAtPixel( | ||
coordinate, frameState, goog.functions.TRUE, this, layerFilter, thisArg); | ||
|
||
return goog.isDef(hasFeature) ? hasFeature : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be goog.isDef(hasFeature) ? true : false;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better: return goog.isDef(hasFeature)
!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously. I was about to edit my comment :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right.
I've just added a pretty minor comment, otherwise looks very good to me. |
|
||
|
||
/** | ||
* @private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be an @enum
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you meant @const
. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I did! ;-)
... with the atlas for the original images, so that the offsets are the same.
Only return the callback result if it is truthy, otherwise return undefined.
6521f05
to
abb5fad
Compare
* @inheritDoc | ||
*/ | ||
ol.renderer.webgl.Map.prototype.hasFeatureAtPixel = | ||
function(coordinate, frameState, layerFilter, thisArg2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor, but the last argument could be named thisArg
(without the 2
).
abb5fad
to
c85982b
Compare
Any other comments? cc @tschaub |
* @api | ||
*/ | ||
ol.Map.prototype.hasFeatureAtPixel = | ||
function(pixel, opt_layerFilter, opt_this2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opt_this2
can be changed to opt_this
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I thought I did this already. :) Fixed in #3108
I just made a comment that @tschaub already made regarding the name Otherwise it looks very good to me. It's good to merge to me. |
Introduce hasFeatureAtPixel
Thanks for reviewing! |
This PR is based on #3065.
#3065 implements hit-detection for WebGL, but unfortunately the performance is not good enough to do hit-detection on
mousemove
(if you have many features). This is because we are callingdrawElements
for every feature, which is expensive.For
mousemove
you are usually not interested in the actual features thatforEachFeatureAtPixel
provides, you just want to know if there is a feature or not, so that you can change the mouse pointer. So in this case you can draw all features at "once" (or to be precise: per texture group) for the hit-detection, and then check if there is a feature or not.That's why we introduced a
hasFeatureAtPixel
method, which simply returnstrue
if there is a feature at the given pixel. For WebGL this function is very fast, for 50000 features it takes less than 20ms (on my system).Example usage:
Example: icon-sprite-webgl.html