Skip to content
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

feature request - a polygon parameter for the QueryRenderedFeatures function #4787

Closed
charliedotau opened this issue Jun 6, 2017 · 11 comments

Comments

@charliedotau
Copy link

I'd like the ability to highlight shapes on a map by drawing a polygon on a map. Essentially very similar to this example - https://www.mapbox.com/mapbox-gl-js/example/using-box-queryrenderedfeatures/ - except instead of drawing a box, I would draw a polygon.

Motivation

The motivation for this change is simply to achieve what the example above achieves, but with a much more accurate tool. A bounding box is a rather blunt instrument - compared to a polygon - for selecting geographic areas.

The larger motivation is to be able to provide non-technical people (such as subject matter experts) a means to provide visual feedback on a map, simply and accurately (and for that means to be simple to implement).

I've built a Feedback tool using Mapbox GL JS and Mapbox GL Draw (see https://github.com/charliedotau/mapbox-gl-js-draw-github-gist) to facilitate easy user feedback on map content. Whilst its great for the user - simple to use - its painful for the map editor (who has to take the GeoJSON in the Gist and run intersect queries against the source map to derive the desired data.

AFAIK, the GL Draw API only allows me to get data about the shape drawn by the user, as opposed to data (e.g properties) of the features on the map under the shape drawn by the user.

Design Alternatives

I know of no other way to achieve the desired outcome using Mapbox.

Design

The UI required for this is the ability to draw a polygon on map (much like Mapbox GL Draw).

Mock-Up

n/a - Draw GL provides all that is needed.

Concepts

n/a

Implementation

I imagine the implementation is two-fold:

  1. extending the QueryRenderedFeatures() method to take a polygon as a parameter and
  2. some UI facility to draw the polygon
@anandthakker
Copy link
Contributor

@charliedotau Thanks for this request, and for explaining your use case!

Using a library like Turf, you should be able to put this feature together by:

  • Use GL draw to allow the user to draw a polygon
  • Use turf.bbox to get the bounding box of the poly
  • Call queryRenderedFeatures using that bounding box
  • Filter the results of the query by testing for the features that intersect the user's polygon, using turf.intersect

I'm closing for now, but please do reopen if this doesn't adequately address the issue

@charliedotau
Copy link
Author

thanks @anandthakker. I hadn't thought of that!

I did a little demo - see https://github.com/charliedotau/mapbox-gl-js-select-features-by-draw

thanks

@shawnmgoulet
Copy link

shawnmgoulet commented Sep 27, 2017

@charliedotau & @anandthakker - this just made my week.

@charliedotau - may I suggest you submit a pull request to add this as an mapbox gl js example. Judging off the stackoverflow activity, I have a feeling it would be helpful to many others.

I recycled this logic to implement the same use case on a feature collection > single polygon added to the map on the click of a button against a feature collection > multiple polygons added once the map is loaded. Works 👌

UPDATE #1: Actually, this method only draws a box that connects the points of the northeast & southwest box, but does not follow the edges of an irregular polygon. So, it's almost doing what I need, but not exactly. I am working on tweaking so my use case is achieved and will share.

UPDATE #2: My project is webpack + vue.js based and I'm actually getting the incorrect (more than expected number) intersecting polygons when running npm run dev, but the correct (expected number) of intersecting polygons running npm run build. 😝 😝

I'm going to test my code base in pure html + js using the SimpleHTTPServer to serve it and see what happens.

@lucageo
Copy link

lucageo commented Dec 12, 2018

Hi @charliedotau & @anandthakker, are there any updates on using queryRenderedFeatures passing a polygon? like this:
var coords = turf.polygon(e.features[0].geometry.coordinates);
var features = map.queryRenderedFeatures(coords, { layers: ['layer_name'] });

Thanks a lot,
Luca

@karimifar
Copy link

Hi everyone!
I see this issue has been closed a while back but this is exactly what I'm looking for and I don't see any response to it. Can someone clarify: can we get all the features that fall under a drawn polygon?

Hi @charliedotau & @anandthakker, are there any updates on using queryRenderedFeatures passing a polygon? like this:
var coords = turf.polygon(e.features[0].geometry.coordinates);
var features = map.queryRenderedFeatures(coords, { layers: ['layer_name'] });

Thanks a lot,
Luca

@sebastian-ch
Copy link

sebastian-ch commented Jul 26, 2021

Hi everyone!
I see this issue has been closed a while back but this is exactly what I'm looking for and I don't see any response to it. Can someone clarify: can we get all the features that fall under a drawn polygon?

Hi @charliedotau & @anandthakker, are there any updates on using queryRenderedFeatures passing a polygon? like this:
var coords = turf.polygon(e.features[0].geometry.coordinates);
var features = map.queryRenderedFeatures(coords, { layers: ['layer_name'] });
Thanks a lot,
Luca

Hello! I think I figured out a way to make this work by adjusting the example put forth by @charliedotau.

Instead of using turf.intersect, I use turf.booleanIntersects for each feature compared with the user input polygon.

var filter = features.reduce(function (memo, feature) {

        //if(! (undefined === turf.intersect(feature, userPolygon))) {
          if(turf.booleanIntersects(feature, userPolygon))  {

            memo.push(feature.properties.hexid);
        }
            return memo;
        },
        ['in', 'hexid']);

ex
in this example, the hexagons are shown if they intersect with the input polygon.

This allows for the intersection to actually use a polygon and not just a rectangle.

@bertday
Copy link

bertday commented Jan 2, 2024

You should be able to do this by setting the filter property of the Map.queryRenderedFeatures options object. Here's an example:

const featuresInsidePolygon = map.queryRenderedFeatures(
  { 
    filter: ['within', somePolygonGeojson],
  },
);

@smarth23
Copy link

Just going to put this here for anyone. This is how got it to work.

const [minLon, minLat, maxLon, maxLat] = turf.bbox(PolygonFeature);
const minCoord = map..project([minLon, minLat]);
const maxCoord = map.project([maxLon, maxLat]);

const bound: [mapboxgl.PointLike, mapboxgl.PointLike] = [minCoord,maxCoord];
const nearbyFeatures = this.map.mapInstance.queryRenderedFeatures(bound,{layers:layerlist,filter: ['within', PolygonFeature]});

@web-iou
Copy link

web-iou commented May 13, 2024

Just going to put this here for anyone. This is how got it to work.

const [minLon, minLat, maxLon, maxLat] = turf.bbox(PolygonFeature); const minCoord = map..project([minLon, minLat]); const maxCoord = map.project([maxLon, maxLat]);

const bound: [mapboxgl.PointLike, mapboxgl.PointLike] = [minCoord,maxCoord]; const nearbyFeatures = this.map.mapInstance.queryRenderedFeatures(bound,{layers:layerlist,filter: ['within', PolygonFeature]});

hey bro
i think your way is right,but sometimes i get empty data by the way. i don t know what s wrong

@web-iou
Copy link

web-iou commented May 13, 2024

i m use mapbox-gl-draw to get a poly feature when i created and updated to use this function to filter layers

@smarth23
Copy link

If you are using "within" filter in queryRenderedFeatures. Layers that are completely inside the polygon bounds will show up. Any intersecting layer will be filtered out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants