Permalink
Browse files

gis: Fixed #7619. Added support Google Maps markers (`GMarker`) and e…

…vents (`GEvent`). Thanks, Ludwig Brinckmann.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7841 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
jbronn committed Jul 5, 2008
1 parent ccd5f52 commit 822a1259f6d81392035e6698e6386b9639e14eec
@@ -57,5 +57,5 @@
version.
"""
from django.contrib.gis.maps.google.gmap import GoogleMap
-from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline
+from django.contrib.gis.maps.google.overlays import GEvent, GMarker, GPolygon, GPolyline
from django.contrib.gis.maps.google.zoom import GoogleZoom
@@ -4,7 +4,7 @@
from django.utils.safestring import mark_safe
class GoogleMapException(Exception): pass
-from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline
+from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker
# The default Google Maps URL (for the API javascript)
# TODO: Internationalize for Japan, UK, etc.
@@ -20,7 +20,7 @@ class GoogleMap(object):
def __init__(self, key=None, api_url=None, version=None,
center=None, zoom=None, dom_id='map', load_func='gmap_load',
- kml_urls=[], polygons=[], polylines=[],
+ kml_urls=[], polygons=[], polylines=[], markers=[],
template='gis/google/js/google-map.js',
extra_context={}):
@@ -55,8 +55,14 @@ def __init__(self, key=None, api_url=None, version=None,
self.template = template
self.kml_urls = kml_urls
- # Does the user want any GPolygon or GPolyline overlays?
- self.polygons, self.polylines = [], []
+ # Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
+ self.polygons, self.polylines, self.markers = [], [], []
+ if markers:
+ for point in markers:
+ if isinstance(point, GMarker):
+ self.markers.append(point)
+ else:
+ self.markers.append(GMarker(point))
if polygons:
for poly in polygons:
if isinstance(poly, GPolygon):
@@ -70,12 +76,13 @@ def __init__(self, key=None, api_url=None, version=None,
else:
self.polylines.append(GPolyline(pline))
- # If GPolygons and/or GPolylines are used the zoom will be automatically
+ # If GMarker, GPolygons, and/or GPolylines
+ # are used the zoom will be automatically
# calculated via the Google Maps API. If both a zoom level and a
# center coordinate are provided with polygons/polylines, no automatic
# determination will occur.
self.calc_zoom = False
- if self.polygons or self.polylines:
+ if self.polygons or self.polylines or self.markers:
if center is None or zoom is None:
self.calc_zoom = True
@@ -95,6 +102,7 @@ def __init__(self, key=None, api_url=None, version=None,
'zoom' : self.zoom,
'polygons' : self.polygons,
'polylines' : self.polylines,
+ 'markers' : self.markers,
}
params.update(extra_context)
self.js = render_to_string(self.template, params)
@@ -1,10 +1,66 @@
-from django.contrib.gis.geos import LineString, LinearRing, Polygon
from django.utils.safestring import mark_safe
+from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon
+
+class GEvent(object):
+ """
+ A Python wrapper for the Google GEvent object.
+
+ Events can be attached to any object derived from GOverlayBase with the
+ add_event() call.
+
+ For more information please see the Google Maps API Reference:
+ http://code.google.com/apis/maps/documentation/reference.html#GEvent
+
+ Example:
+
+ from django.shortcuts import render_to_response
+ from django.contrib.gis.maps.google import GoogleMap, GEvent, GPolyline
+
+ def sample_request(request):
+ polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)')
+ event = GEvent('click',
+ 'function() { location.href = "http://www.google.com"}')
+ polyline.add_event(event)
+ return render_to_response('mytemplate.html',
+ {'google' : GoogleMap(polylines=[polyline])})
+ """
+
+ def __init__(self, event, action):
+ """
+ Initializes a GEvent object.
+
+ Parameters:
+
+ event:
+ string for the event, such as 'click'. The event must be a valid
+ event for the object in the Google Maps API.
+ There is no validation of the event type within Django.
+
+ action:
+ string containing a Javascript function, such as
+ 'function() { location.href = "newurl";}'
+ The string must be a valid Javascript function. Again there is no
+ validation fo the function within Django.
+ """
+ self.event = event
+ self.action = action
+
+ def __unicode__(self):
+ "Returns the parameter part of a GEvent."
+ return mark_safe('"%s", %s' %(self.event, self.action))
class GOverlayBase(object):
+ def __init__(self):
+ self.events = []
+
def latlng_from_coords(self, coords):
+ "Generates a JavaScript array of GLatLng objects for the given coordinates."
return '[%s]' % ','.join(['new GLatLng(%s,%s)' % (y, x) for x, y in coords])
+ def add_event(self, event):
+ "Attaches a GEvent to the overlay object."
+ self.events.append(event)
+
def __unicode__(self):
"The string representation is the JavaScript API call."
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
@@ -19,8 +75,9 @@ def __init__(self, poly,
stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1,
fill_color='#0000ff', fill_opacity=0.4):
"""
- The GPolygon object initializes on a GEOS Polygon. Please note that
- this will not depict Polygons with internal rings.
+ The GPolygon object initializes on a GEOS Polygon or a parameter that
+ may be instantiated into GEOS Polygon. Please note that this will not
+ depict a Polygon's internal rings.
Keyword Options:
@@ -39,8 +96,8 @@ def __init__(self, poly,
fill_opacity:
The opacity of the polygon fill. Defaults to 0.4.
"""
-
- # TODO: Take other types of geometries.
+ if isinstance(poly, basestring): poly = fromstr(poly)
+ if isinstance(poly, (tuple, list)): poly = Polygon(poly)
if not isinstance(poly, Polygon):
raise TypeError('GPolygon may only initialize on GEOS Polygons.')
@@ -57,7 +114,9 @@ def __init__(self, poly,
# Fill settings.
self.fill_color, self.fill_opacity = fill_color, fill_opacity
-
+
+ super(GPolygon, self).__init__()
+
@property
def js_params(self):
return '%s, "%s", %s, %s, "%s", %s' % (self.points, self.stroke_color, self.stroke_weight, self.stroke_opacity,
@@ -71,8 +130,9 @@ class GPolyline(GOverlayBase):
"""
def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
"""
- The GPolyline object may initialize on GEOS LineStirng, LinearRing,
- and Polygon objects (internal rings not supported).
+ The GPolyline object may be initialized on GEOS LineStirng, LinearRing,
+ and Polygon objects (internal rings not supported) or a parameter that
+ may instantiated into one of the above geometries.
Keyword Options:
@@ -85,6 +145,10 @@ def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
opacity:
The opacity of the polyline, between 0 and 1. Defaults to 1.
"""
+ # If a GEOS geometry isn't passed in, try to contsruct one.
+ if isinstance(geom, basestring): geom = fromstr(geom)
+ if isinstance(geom, (tuple, list)): geom = Polygon(geom)
+ # Generating the lat/lng coordinate pairs.
if isinstance(geom, (LineString, LinearRing)):
self.latlngs = self.latlng_from_coords(geom.coords)
elif isinstance(geom, Polygon):
@@ -95,7 +159,62 @@ def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
# Getting the envelope for automatic zoom determination.
self.envelope = geom.envelope
self.color, self.weight, self.opacity = color, weight, opacity
+ super(GPolyline, self).__init__()
@property
def js_params(self):
return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity)
+
+class GMarker(GOverlayBase):
+ """
+ A Python wrapper for the Google GMarker object. For more information
+ please see the Google Maps API Reference:
+ http://code.google.com/apis/maps/documentation/reference.html#GMarker
+
+ Example:
+
+ from django.shortcuts import render_to_response
+ from django.contrib.gis.maps.google.overlays import GMarker, GEvent
+
+ def sample_request(request):
+ marker = GMarker('POINT(101 26)')
+ event = GEvent('click',
+ 'function() { location.href = "http://www.google.com"}')
+ marker.add_event(event)
+ return render_to_response('mytemplate.html',
+ {'google' : GoogleMap(markers=[marker])})
+ """
+ def __init__(self, geom, title=None):
+ """
+ The GMarker object may initialize on GEOS Points or a parameter
+ that may be instantiated into a GEOS point. Keyword options map to
+ GMarkerOptions -- so far only the title option is supported.
+
+ Keyword Options:
+ title:
+ Title option for GMarker, will be displayed as a tooltip.
+ """
+ # If a GEOS geometry isn't passed in, try to construct one.
+ if isinstance(geom, basestring): geom = fromstr(geom)
+ if isinstance(geom, (tuple, list)): geom = Point(geom)
+ if isinstance(geom, Point):
+ self.latlng = self.latlng_from_coords(geom.coords)
+ else:
+ raise TypeError('GMarker may only initialize on GEOS Point geometry.')
+ # Getting the envelope for automatic zoom determination.
+ self.envelope = geom.envelope
+ # TODO: Add support for more GMarkerOptions
+ self.title = title
+ super(GMarker, self).__init__()
+
+ def latlng_from_coords(self, coords):
+ return 'new GLatLng(%s,%s)' %(coords[1], coords[0])
+
+ def options(self):
+ result = []
+ if self.title: result.append('title: "%s"' % self.title)
+ return '{%s}' % ','.join(result)
+
+ @property
+ def js_params(self):
+ return '%s, %s' % (self.latlng, self.options())
@@ -3,17 +3,28 @@
{% block load %}function {{ load_func }}(){
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("{{ dom_id }}"));
+ map.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }});
{% block controls %}map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());{% endblock %}
- {% if calc_zoom %}var bounds = new GLatLngBounds(); var tmp_bounds = new GLatLngBounds();{% else %}map.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }});{% endif %}
+ {% if calc_zoom %}var bounds = new GLatLngBounds(); var tmp_bounds = new GLatLngBounds();{% endif %}
{% for kml_url in kml_urls %}var kml{{ forloop.counter }} = new GGeoXml("{{ kml_url }}");
map.addOverlay(kml{{ forloop.counter }});{% endfor %}
+
{% for polygon in polygons %}var poly{{ forloop.counter }} = new {{ polygon }};
- map.addOverlay(poly{{ forloop.counter }});{% if calc_zoom %}
- tmp_bounds = poly{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %}
+ map.addOverlay(poly{{ forloop.counter }});
+ {% for event in polygon.events %}GEvent.addListener(poly{{ forloop.parentloop.counter }}, {{ event }});{% endfor %}
+ {% if calc_zoom %}tmp_bounds = poly{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %}
+
{% for polyline in polylines %}var polyline{{ forloop.counter }} = new {{ polyline }};
- map.addOverlay(polyline{{ forloop.counter }});{% if calc_zoom %}
- tmp_bounds = polyline{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %}
+ map.addOverlay(polyline{{ forloop.counter }});
+ {% for event in polyline.events %}GEvent.addListener(polyline{{ forloop.parentloop.counter }}, {{ event }}); {% endfor %}
+ {% if calc_zoom %}tmp_bounds = polyline{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %}
+
+ {% for marker in markers %}var marker{{ forloop.counter }} = new {{ marker }};
+ map.addOverlay(marker{{ forloop.counter }});
+ {% for event in marker.events %}GEvent.addListener(marker{{ forloop.parentloop.counter }}, {{ event }}); {% endfor %}
+ {% if calc_zoom %}bounds.extend(marker{{ forloop.counter }}.getLatLng()); {% endif %}{% endfor %}
+
{% if calc_zoom %}map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));{% endif %}
{% block load_extra %}{% endblock %}
}else {

0 comments on commit 822a125

Please sign in to comment.