Randoom a Michael Friis production

Posted
8 March 2010 @ 1am

Categories
Django, Javascript

Tagged
, ,

You're reading Randoom, a Michael Friis production

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;
}

9 Comments

Posted by
Jason
19 March 2010 @ 3am

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!


Posted by
friism
19 March 2010 @ 8pm

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.


Posted by
Jason
19 March 2010 @ 8pm

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 _.


Posted by
Haes
25 May 2010 @ 10am

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.


Posted by
Steve
23 July 2010 @ 10pm

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 :D


Posted by
friism
23 July 2010 @ 10pm

@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.


Posted by
Steve
26 July 2010 @ 4pm

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);
};


Posted by
Kevin
2 March 2012 @ 11pm

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!


Posted by
admin
2 March 2012 @ 11pm

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

Michael


Leave a Comment