Michael Friis' Blog

About


Drawing geojson-based polygons on Google Maps

This post will demonstrate how to draw polygons on Google Maps v3 using geojson-encoded data from GeoDjango. The most common method for displaying polygons on Google Maps seems to be by using KML. Google Maps requires the KML-file to be available on a public website though and that is kind of a bore for debugging. This approach uses only json and the standard maps drawing API. To get the display the polygons, you have to loop over them and do a setMap() with your map.

I’m assuming the browser is getting geojson from from a GeoDjango model object like this: model.area.geojson, but it should work for data from other sources. Note that I’m using the very excellent Underscore.js Javascript library to do really terse functional programming. Also note that the function takes an optional bounds object which gets expanded as polygon points are added.

The code seems to perform very well in modern browsers, even for fairly large and complex polygons. Unfortunately there is no live demo, but the site I’m working on should go up soon.

function createPolygons(areajson, bounds){
  var coords = areajson.coordinates;
  var polygons = _(coords).reduce([], function(memo_n, n) {
    var polygonpaths = _(n).reduce(new google.maps.MVCArray(), function(memo_o, o) {
      var polygoncords = _(o).reduce(new google.maps.MVCArray(), function(memo_p, p) {
        var mylatlng = new google.maps.LatLng(p[1], p[0]);
        if(bounds){
          bounds.extend(mylatlng);
        }
        memo_p.push(mylatlng);
        return memo_p;
      });
      memo_o.push(polygoncords);
      return memo_o;
    });
    var polygon = new google.maps.Polygon({
      paths: polygonpaths,
      strokeColor: "#808080",
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: "#C0C0C0",
      fillOpacity: 0.35
    });
    memo_n.push(polygon);
    return memo_n;
  });
  return polygons;
}

Comments

Jason on

Do you know if this method works with “Polygon” and “MultiPolygon” formatted JSON? I was looking for some help creating polygons from “MultiPolygon” formatted JSON using jQuery and found this site. I might have to give underscore a look!

Reply

friism on

I use this code for rendering Multipolygons, and it works great, both for areas consisting of several disjoint polygons and for areas with “holes” in them.

Reply

Jason on

I should have updated my comment earlier. I’m using your code and it works beautifully. Now if I can only understand why…off to study some _.

Reply

Haes on

Thanks for this blog entry. Would you care to post a complete example, including a view and the rest of the javascript in the template?
I’m having some difficulties to get this running and I’m not quite sure what’s the problem.

Reply

Steve on

Where in this are you passing in your geojson? I guess that you wanted it like…

var coords = {{mymodel.geom.geojson}}

but that obv doesn’t work. Also, where are you initializing the map? I don’t need the view but the template sure would help me 😀

Reply

friism on

@Steve: I’m passing in the geojson in the ‘areajson’ parameter. And I output it the way you mention, although I pass through the |safe filter. Why is this not working for you?

The map init code is not in the snippet above, but it is not directly relevant. Just remember that when you have both map and polygons going, you need to call setMap(map) on each polygon.

Reply

Steve on

Here is the complete view as I have it, where zipcode is a multipolygon with four paths:

html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map_canvas { height: 100% }

function initialize() {
var latlng = new google.maps.LatLng({{ zipcode.geom.centroid.y}},
{{ zipcode.geom.centroid.x}});
var myOptions = {
zoom: {{ zoom }},
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById(“map_canvas”),
myOptions);

function createPolygons(areajson, bounds){
var coords = {{zipcode.geom.geojson|safe}};
var polygons = _(coords).reduce([], function(memo_n, n) {
var polygonpaths = _(n).reduce(new google.maps.MVCArray(), function(memo_o, o) {
var polygoncords = _(o).reduce(new google.maps.MVCArray(), function(memo_p, p) {
var mylatlng = new google.maps.LatLng(p[1], p[0]);
if(bounds){
bounds.extend(mylatlng);
}
memo_p.push(mylatlng);
return memo_p;
});
memo_o.push(polygoncords);
return memo_o;
});
var polygon = new google.maps.Polygon({
paths: polygonpaths,
strokeColor: “#808080”,
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: “#C0C0C0”,
fillOpacity: 0.35
});
memo_n.push(polygon);
return memo_n;
});
return polygons;
};
polygon.setMap(map);
};

Reply

Kevin on

Hi Michel, not sure if you’re still monitoring this post, but when I try to run it I get an error from underscore.js saying ‘Uncaught TypeError: is not a function’ – has something changed in underscore since you wrote your code? Thanks for any insight you can provide!

Reply

admin on

@Kevin, I haven’t looked at this recently, you may have to debug it yourself.

Michael

Reply

Leave a Reply

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