Polygons and overlays with Google Maps v3 API

I stopped short of displaying an equivalent overlay in Google Maps v3 yesterday, but wanted to circle back and show that it’s doable as well. It’s far more verbose than the magic-y “pass it a polygon and it does the rest”, but you have more control too.

View, pretty much just like the one we used for points only with a model that has a polygon:

def gmap3_poly(request):
    states = State.objects.filter(mpoly__distance_lte=(Point((-94, 37)), D(mi=100)))

    return render_to_response('gmap3.html', {
        'object_list': states,
    }, context_instance=RequestContext(request))

For the template, I actually modified yesterday’s to auto-detect the geometry coming through and just do the right thing.

{% extends "gmap3base.html" %}

{% block page-title %}Requested Items{% endblock %}

{% block head_override %}
<script type="text/javascript">
  var bounds = new google.maps.LatLngBounds();

  function buildMarker(map, latitude, longitude, name, color) {
    var latlng = new google.maps.LatLng(latitude, longitude);
    var marker = new google.maps.Marker({
          position: latlng,
          map: map,
          title:name,
    });
    marker.setIcon('http://maps.google.com/mapfiles/ms/icons/' + color + '-dot.png');
    bounds.extend(latlng);
    return marker
  }

  function mapInitialize() {
    var myOptions = {
      zoom: 6,
      center: new google.maps.LatLng(0, 0),
      mapTypeId: google.maps.MapTypeId.SATELLITE
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"),
        myOptions);

    {% for object in object_list %}
    {% if object.point %}marker{{ object.pk }} = buildMarker(map, {{ object.point.y }}, {{ object.point.x }}, "{{ object }}", 'red');
    {% endif %}
    {% if object.mpoly %}
    var polygon{{ object.pk }}Coords = [
    {% with object.mpoly.0.0 as the_polygon %}
    {% for point in the_polygon %}
        new google.maps.LatLng({{ point.1 }}, {{ point.0 }}),
    {% endfor %}
    {% endwith %}
    ];

    var the_polygon{{ object.pk }} = new google.maps.Polygon({
      paths: polygon{{ object.pk }}Coords,
      strokeColor: "#FF0000",
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: "#FF0000",
      fillOpacity: 0.35
    });

    for (i = 0; i < polygon{{ object.pk }}Coords.length; i++) {
      bounds.extend(polygon{{ object.pk }}Coords[i]);
    }

    the_polygon{{ object.pk }}.setMap(map);
    {% endif %}
    {% endfor %}

    map.fitBounds(bounds);
  }

</script>
{% endblock head_override %}

{% block body_override %} onload="mapInitialize()"{% endblock body_override %}

{% block content %}
<div id="map_canvas" style='width:600px;height:400px;'></div>
{% endblock content %}

Rendered out, the (4.4MB) file looks like this.

But we want our apps to be more interactive – so let’s quickly add popup windows when something is clicked on. The blog isn’t going to handle a diff very well, and that’s the best way to show it, so check out this gist. It’s not very difficult at all. Now we get popups when somebody clicks a marker, without writing a single line of view code. I tend to build methods on my models for map_display_html() or something similar. If I’m really returning HTML I’ll put it in a template and use the template language to make it work, if it’s just a name and hyperlink or something similar I just leave it in the model.

Leave a Reply

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