1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

gis: Fixed #7619. Added support Google Maps markers (GMarker) and events (GEvent). Thanks, Ludwig Brinckmann.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7841 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2008-07-05 22:10:33 +00:00
parent ccd5f52ee7
commit 822a1259f6
4 changed files with 158 additions and 20 deletions

View File

@ -57,5 +57,5 @@
version. version.
""" """
from django.contrib.gis.maps.google.gmap import GoogleMap 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 from django.contrib.gis.maps.google.zoom import GoogleZoom

View File

@ -4,7 +4,7 @@ from django.template.loader import render_to_string
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
class GoogleMapException(Exception): pass 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) # The default Google Maps URL (for the API javascript)
# TODO: Internationalize for Japan, UK, etc. # TODO: Internationalize for Japan, UK, etc.
@ -20,7 +20,7 @@ class GoogleMap(object):
def __init__(self, key=None, api_url=None, version=None, def __init__(self, key=None, api_url=None, version=None,
center=None, zoom=None, dom_id='map', load_func='gmap_load', 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', template='gis/google/js/google-map.js',
extra_context={}): extra_context={}):
@ -55,8 +55,14 @@ class GoogleMap(object):
self.template = template self.template = template
self.kml_urls = kml_urls self.kml_urls = kml_urls
# Does the user want any GPolygon or GPolyline overlays? # Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
self.polygons, self.polylines = [], [] 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: if polygons:
for poly in polygons: for poly in polygons:
if isinstance(poly, GPolygon): if isinstance(poly, GPolygon):
@ -70,12 +76,13 @@ class GoogleMap(object):
else: else:
self.polylines.append(GPolyline(pline)) 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 # calculated via the Google Maps API. If both a zoom level and a
# center coordinate are provided with polygons/polylines, no automatic # center coordinate are provided with polygons/polylines, no automatic
# determination will occur. # determination will occur.
self.calc_zoom = False 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: if center is None or zoom is None:
self.calc_zoom = True self.calc_zoom = True
@ -95,6 +102,7 @@ class GoogleMap(object):
'zoom' : self.zoom, 'zoom' : self.zoom,
'polygons' : self.polygons, 'polygons' : self.polygons,
'polylines' : self.polylines, 'polylines' : self.polylines,
'markers' : self.markers,
} }
params.update(extra_context) params.update(extra_context)
self.js = render_to_string(self.template, params) self.js = render_to_string(self.template, params)

View File

@ -1,10 +1,66 @@
from django.contrib.gis.geos import LineString, LinearRing, Polygon
from django.utils.safestring import mark_safe 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): class GOverlayBase(object):
def __init__(self):
self.events = []
def latlng_from_coords(self, coords): 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]) 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): def __unicode__(self):
"The string representation is the JavaScript API call." "The string representation is the JavaScript API call."
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params)) return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
@ -19,8 +75,9 @@ class GPolygon(GOverlayBase):
stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1, stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1,
fill_color='#0000ff', fill_opacity=0.4): fill_color='#0000ff', fill_opacity=0.4):
""" """
The GPolygon object initializes on a GEOS Polygon. Please note that The GPolygon object initializes on a GEOS Polygon or a parameter that
this will not depict Polygons with internal rings. may be instantiated into GEOS Polygon. Please note that this will not
depict a Polygon's internal rings.
Keyword Options: Keyword Options:
@ -39,8 +96,8 @@ class GPolygon(GOverlayBase):
fill_opacity: fill_opacity:
The opacity of the polygon fill. Defaults to 0.4. The opacity of the polygon fill. Defaults to 0.4.
""" """
if isinstance(poly, basestring): poly = fromstr(poly)
# TODO: Take other types of geometries. if isinstance(poly, (tuple, list)): poly = Polygon(poly)
if not isinstance(poly, Polygon): if not isinstance(poly, Polygon):
raise TypeError('GPolygon may only initialize on GEOS Polygons.') raise TypeError('GPolygon may only initialize on GEOS Polygons.')
@ -58,6 +115,8 @@ class GPolygon(GOverlayBase):
# Fill settings. # Fill settings.
self.fill_color, self.fill_opacity = fill_color, fill_opacity self.fill_color, self.fill_opacity = fill_color, fill_opacity
super(GPolygon, self).__init__()
@property @property
def js_params(self): def js_params(self):
return '%s, "%s", %s, %s, "%s", %s' % (self.points, self.stroke_color, self.stroke_weight, self.stroke_opacity, 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): def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
""" """
The GPolyline object may initialize on GEOS LineStirng, LinearRing, The GPolyline object may be initialized on GEOS LineStirng, LinearRing,
and Polygon objects (internal rings not supported). and Polygon objects (internal rings not supported) or a parameter that
may instantiated into one of the above geometries.
Keyword Options: Keyword Options:
@ -85,6 +145,10 @@ class GPolyline(GOverlayBase):
opacity: opacity:
The opacity of the polyline, between 0 and 1. Defaults to 1. 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)): if isinstance(geom, (LineString, LinearRing)):
self.latlngs = self.latlng_from_coords(geom.coords) self.latlngs = self.latlng_from_coords(geom.coords)
elif isinstance(geom, Polygon): elif isinstance(geom, Polygon):
@ -95,7 +159,62 @@ class GPolyline(GOverlayBase):
# Getting the envelope for automatic zoom determination. # Getting the envelope for automatic zoom determination.
self.envelope = geom.envelope self.envelope = geom.envelope
self.color, self.weight, self.opacity = color, weight, opacity self.color, self.weight, self.opacity = color, weight, opacity
super(GPolyline, self).__init__()
@property @property
def js_params(self): def js_params(self):
return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity) 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())

View File

@ -3,17 +3,28 @@
{% block load %}function {{ load_func }}(){ {% block load %}function {{ load_func }}(){
if (GBrowserIsCompatible()) { if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("{{ dom_id }}")); map = new GMap2(document.getElementById("{{ dom_id }}"));
map.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }});
{% block controls %}map.addControl(new GSmallMapControl()); {% block controls %}map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());{% endblock %} 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 }}"); {% for kml_url in kml_urls %}var kml{{ forloop.counter }} = new GGeoXml("{{ kml_url }}");
map.addOverlay(kml{{ forloop.counter }});{% endfor %} map.addOverlay(kml{{ forloop.counter }});{% endfor %}
{% for polygon in polygons %}var poly{{ forloop.counter }} = new {{ polygon }}; {% for polygon in polygons %}var poly{{ forloop.counter }} = new {{ polygon }};
map.addOverlay(poly{{ forloop.counter }});{% if calc_zoom %} map.addOverlay(poly{{ forloop.counter }});
tmp_bounds = poly{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %} {% 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 }}; {% for polyline in polylines %}var polyline{{ forloop.counter }} = new {{ polyline }};
map.addOverlay(polyline{{ forloop.counter }});{% if calc_zoom %} map.addOverlay(polyline{{ forloop.counter }});
tmp_bounds = polyline{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %} {% 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 %} {% if calc_zoom %}map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));{% endif %}
{% block load_extra %}{% endblock %} {% block load_extra %}{% endblock %}
}else { }else {