Filter Geolocation By Bounding Box

Hey there,

Loving Dato so far and the continued efforts of the team to improve the platform!

One thing my team thinks is missing (and could desperately do with!) is filtering Geolocation fields by a bounding box. This would open up the ability to efficiently filter by the “view” of a map, allowing developers to implement an Airbnb-style maps.

Currently the CDA only supports filtering by a radius from a central point which is great, but has limitations such as:

  1. Loading in out-of-view content in (to cover a square/rectangular viewport)

  2. Troubles when changing between zoom levels, bringing a lot of guess work into deciding the size of the radius to use

Any plans on implementing something like this?

Thanks!

Ben

Hi @benjamincbialy,

Good idea (please remember to vote on it in the upper left!), and this would help make our geo field more powerful, for sure. I don’t think there are any current plans for it, unfortunately, but hopefully someday!

In the meantime, just as a workaround, you can use the Computed Fields plugin to derive the selected location into separate lng and lat float fields, like this:

That would auto-update those derived number fields whenever the real location field changes.

Then you can query it with a bounding box in GraphQL using a filter like this:

query MyQuery {
  allExampleModels(
    filter: {
      lat: {gte: "43.763067", lte: "43.775138"},
      lng: {gte: "11.237233", lte: "11.264741"}}
  ) {
    location {
      latitude
      longitude
    }
  }
}

Where the gte and lte values are your bounding box, e.g.:


Alternatively, if you don’t have too many locations to begin with (< a few hundred, maybe?), I might consider fetching ALL of them upfront (or at least within a huge radius) and then just filtering them clientside. POI data isn’t usually that big over the wire (especially gzipped), and it can make the map browsing/searching/filtering a lot faster if the client already has all of them cached locally.

You can also mathematically calculate a radius (in meters) from a bounding box or viewport extent and query that: https://stackoverflow.com/questions/75454365/leaflet-draw-a-circle-that-fits-around-a-bounding-box

e.g. if you’re using a geo library like Leaflet, latLng.distanceTo() will convert to meters for you:


/**
 * Bounding box in (lat,lng) degrees:
 * - southWest = (minLat, minLng)
 * - northEast = (maxLat, maxLng)
 */
const circleThatEnclosesBBox = (bbox) => {
  const bounds = L.latLngBounds(
    L.latLng(bbox.minLat, bbox.minLng),
    L.latLng(bbox.maxLat, bbox.maxLng),
  );

  const center = bounds.getCenter();

  const sw = bounds.getSouthWest();
  const se = L.latLng(bounds.getSouth(), bounds.getEast());
  const ne = bounds.getNorthEast();
  const nw = L.latLng(bounds.getNorth(), bounds.getWest());

  const radiusMeters = Math.max(
    center.distanceTo(sw),
    center.distanceTo(se),
    center.distanceTo(ne),
    center.distanceTo(nw),
  );

  return { center, radiusMeters, bounds };
};

Or a single-page example (must be run locally due to CSP):

example.html (4.3 KB)

If you’re not using a lib, Leaflet’s code for distanceTo() is at https://github.com/Leaflet/Leaflet/blob/main/src/geo/crs/EarthCRS.js#L16-L32

It uses the https://en.wikipedia.org/wiki/Haversine_formula, which should be a good-enough approximation for a use case like this.


(But again, this doesn’t in any way take away from the validity of the original request… I agree that it’d be a useful thing for us to support serverside, instead of making you jump through hoops like these!)

1 Like

Hi Roger,

Thanks for your thoughtful responses.

Unfortunately we have several thousand POIs and expect to scale that up into the tens of thousands very soon so client side options aren’t ideal.

The computed fields option should work great though. Good thinking!

Thanks,

Ben

1 Like

Gotcha. Thanks for understanding, and hope the computed fields solution works for now! I’ll let you know if we ever implement the serverside filters.

1 Like