Use small bounding box instead of circle for map hit detection#1430
Merged
Use small bounding box instead of circle for map hit detection#1430
Conversation
ktuite
commented
Dec 6, 2025
matthew-white
approved these changes
Dec 6, 2025
8ddeced to
7f6c3f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes getodk/central#1455
Removes radial distance check that made use of
getClosestPoint.Longer explanation:
In the function
getHits(pixel)ingeojson-map.vue, there's a two step process:1. getFeaturesAtPixel(pixel, ...)
(OpenLayers docs)
Internally, this calls
renderer_.forEachFeatureAtCoordinate(source code). This function is based on the rendering/visualization of the features, e.g. the glow/highlight on a line would count, and everything in the upside down tear map marker would count as a hit.Since we're using webgl vector layers, it calls the webgl renderer's version of that function, which is only capable of returning a single feature.
2. forEachFeatureNearPixel(source, pixel, ...)
This is our own function that makes up for the fact that with webgl,
getFeaturesAtPixelonly returns one feature, even if the click hits multiple features.This uses the feature data representation (e.g. the coordinates of a point, or the coordinates representing lines and polygons) instead of their rendering. See how 'featureSource' and 'clusterSource' are passed in.
To get multiple features around a click, we construct a small extent/bounding box and use
forEachFeatureIntersectingExtent(docs) to mathematically compare all source features with the extent.We used to further filter this result (of matching features) by checking features within a circular radius within the bounding box. That involved a call to
geometry.getClosestPoint(), which returned the closest point on the boundary of a polygon. If you clicked inside a polygon and the click was not within the hit radius, it wouldn't get flagged as a hit.Actually, one of the polygons would be a hit because it was detected in the first step, but the second polygon wouldn't be a hit for the above reason.
This PR just removes that circle radius check. If the radius is small (e.g. <10 pixels) the extra hit detection are inside the bounding box and outside the circular radius are negligible.
What has been done to verify that this works as intended?
I tried it on the one known problem case, but we should revisit related problem scenarios, too.
Why is this the best possible solution? Were any other approaches considered?
I was hoping there would be some other trick within OpenLayers, or that getFeaturesAtPixel could be made to return multiple features with webgl layers, but I don't think there's a way. I'm convinced that our 2 step process is necessary. But now it's a bit simpler.
How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?
Should improve map UX a little bit. Hopefully doesn't make other things worse.
Does this change require updates to user documentation? If so, please file an issue here and include the link below.
Before submitting this PR, please make sure you have:
npm run testandnpm run lintand confirmed all checks still pass OR confirm CircleCI build passes