Google Maps API data management

Post by Luke Bredeson

When using the Google Maps API, there are some challenges you can encounter with large datasets.  Not only can the server-side queries and browser rendering be time consuming, but there are also visual concerns.

Beware of too many markers

If you don’t group or filter the data somehow, and you have a large dataset, you might end up with something like this:

At first glance, there might be some natural grouping or filtering of data that the application can do, so different zoom levels trigger different AJAX calls (maybe grouped by state, county, city, etc.). When the user zooms in further, then, it becomes safe to show them more data, as the markers that are rendered won’t be piled on top of each other, and when they zoom out, they’re shown sparser groupings of data, to avoid unnecessarily pulling in to much information. You could do something like this:

google.maps.event.addListener(map, 'zoom_changed', function() {
  var zoomLevel = map.getZoom();

  if (zoomLevel <= 5) {
    getData('county');
  } else {
    getData('city');
  }
});

Our getData function just makes AJAX calls and renders google.maps.Marker’s on callback, each of which contain data received from the server. It also makes decisions about what data to fetch based on the specified type of data. This all would be fine, of course, if we wanted to fetch and render all of the data specified by each zoom level, but it would be nice to go a step further and only get the data that falls within the map window.

Bounding boxes in the browser

The Google Maps API can tell you the southwest and northeast corners of the current viewable area, and here is how you can use them:

Let’s discard our previous listener, and replace it with this:

google.maps.event.addListener(map, 'idle', function() {
  var zoomLevel = map.getZoom();
  var southWest = map.getBounds().getSouthWest();
  var northEast = map.getBounds().getNorthEast();
  var box = [[southWest.lng(), southWest.lat()], [northEast.lng(), northEast.lat()]];

  if (zoomLevel <= 5) {
    getData('county', box);
  } else {
    getData('city', box);
  }
});

Now our getData function has an additional responsibility: pass on the bounding box coordinates to the server.

Bounding boxes on the server

There are a number of options for dealing with geospatial data on the server, most notably PostGIS and MongoDB. PostGIS is undoubtably much more fully featured, but MongoDB’s approach is very simple and straightforward, so we’ll use that. Your MongoDB query might look something like this, with parameters having been parsed from the HTTP request:

db.items.find({ "location": { "$within": { "$box": [[-93.515500, 44.859586], [-93.076047, 45.114062]] } })

As long as the “location” property in your “items” collection has a 2d index on it, you now should only be retrieving data from the server that is within Google Maps’ bounds.

This entry was posted in Software Development and tagged , . Bookmark the permalink.

Related Posts:

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>