mirror of https://github.com/django/django.git
Fixed #9204 -- Added `GIcon` overlay, allowing customization for icons of `GMarker` objects. Thanks to qingfeng for initial ticket/patch, and to prairiedogg for final implementation.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@10021 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
326c5813b9
commit
6aa5aacc86
|
@ -57,5 +57,5 @@
|
||||||
version.
|
version.
|
||||||
"""
|
"""
|
||||||
from django.contrib.gis.maps.google.gmap import GoogleMap, GoogleMapSet
|
from django.contrib.gis.maps.google.gmap import GoogleMap, GoogleMapSet
|
||||||
from django.contrib.gis.maps.google.overlays import GEvent, GMarker, GPolygon, GPolyline
|
from django.contrib.gis.maps.google.overlays import GEvent, GIcon, GMarker, GPolygon, GPolyline
|
||||||
from django.contrib.gis.maps.google.zoom import GoogleZoom
|
from django.contrib.gis.maps.google.zoom import GoogleZoom
|
||||||
|
|
|
@ -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, GMarker
|
from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker, GIcon
|
||||||
|
|
||||||
# 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.
|
||||||
|
@ -18,11 +18,12 @@ class GoogleMap(object):
|
||||||
vml_css = mark_safe('v\:* {behavior:url(#default#VML);}') # CSS for IE VML
|
vml_css = mark_safe('v\:* {behavior:url(#default#VML);}') # CSS for IE VML
|
||||||
xmlns = mark_safe('xmlns:v="urn:schemas-microsoft-com:vml"') # XML Namespace (for IE VML).
|
xmlns = mark_safe('xmlns:v="urn:schemas-microsoft-com:vml"') # XML Namespace (for IE VML).
|
||||||
|
|
||||||
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',
|
center=None, zoom=None, dom_id='map',
|
||||||
kml_urls=[], polygons=[], polylines=[], markers=[],
|
kml_urls=[], polylines=None, polygons=None, markers=None,
|
||||||
template='gis/google/google-single.js',
|
template='gis/google/google-single.js',
|
||||||
js_module='geodjango',extra_context={}):
|
js_module='geodjango',
|
||||||
|
extra_context={}):
|
||||||
|
|
||||||
# The Google Maps API Key defined in the settings will be used
|
# The Google Maps API Key defined in the settings will be used
|
||||||
# if not passed in as a parameter. The use of an API key is
|
# if not passed in as a parameter. The use of an API key is
|
||||||
|
@ -34,7 +35,7 @@ class GoogleMap(object):
|
||||||
raise GoogleMapException('Google Maps API Key not found (try adding GOOGLE_MAPS_API_KEY to your settings).')
|
raise GoogleMapException('Google Maps API Key not found (try adding GOOGLE_MAPS_API_KEY to your settings).')
|
||||||
else:
|
else:
|
||||||
self.key = key
|
self.key = key
|
||||||
|
|
||||||
# Getting the Google Maps API version, defaults to using the latest ("2.x"),
|
# Getting the Google Maps API version, defaults to using the latest ("2.x"),
|
||||||
# this is not necessarily the most stable.
|
# this is not necessarily the most stable.
|
||||||
if not version:
|
if not version:
|
||||||
|
@ -55,28 +56,24 @@ class GoogleMap(object):
|
||||||
self.js_module = js_module
|
self.js_module = js_module
|
||||||
self.template = template
|
self.template = template
|
||||||
self.kml_urls = kml_urls
|
self.kml_urls = kml_urls
|
||||||
|
|
||||||
# Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
|
# Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
|
||||||
self.polygons, self.polylines, self.markers = [], [], []
|
overlay_info = [[GMarker, markers, 'markers'],
|
||||||
if markers:
|
[GPolygon, polygons, 'polygons'],
|
||||||
for point in markers:
|
[GPolyline, polylines, 'polylines']]
|
||||||
if isinstance(point, GMarker):
|
|
||||||
self.markers.append(point)
|
for overlay_class, overlay_list, varname in overlay_info:
|
||||||
else:
|
setattr(self, varname, [])
|
||||||
self.markers.append(GMarker(point))
|
if overlay_list:
|
||||||
if polygons:
|
for overlay in overlay_list:
|
||||||
for poly in polygons:
|
if isinstance(overlay, overlay_class):
|
||||||
if isinstance(poly, GPolygon):
|
getattr(self, varname).append(overlay)
|
||||||
self.polygons.append(poly)
|
else:
|
||||||
else:
|
getattr(self, varname).append(overlay_class(overlay))
|
||||||
self.polygons.append(GPolygon(poly))
|
|
||||||
if polylines:
|
# Pulling any icons from the markers.
|
||||||
for pline in polylines:
|
self.icons = [marker.icon for marker in self.markers if marker.icon]
|
||||||
if isinstance(pline, GPolyline):
|
|
||||||
self.polylines.append(pline)
|
|
||||||
else:
|
|
||||||
self.polylines.append(GPolyline(pline))
|
|
||||||
|
|
||||||
# If GMarker, GPolygons, and/or GPolylines are used the zoom will be
|
# If GMarker, GPolygons, and/or GPolylines are used the zoom will be
|
||||||
# automatically calculated via the Google Maps API. If both a zoom
|
# automatically calculated via the Google Maps API. If both a zoom
|
||||||
# level and a center coordinate are provided with polygons/polylines,
|
# level and a center coordinate are provided with polygons/polylines,
|
||||||
|
@ -85,7 +82,7 @@ class GoogleMap(object):
|
||||||
if self.polygons or self.polylines or self.markers:
|
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
|
||||||
|
|
||||||
# Defaults for the zoom level and center coordinates if the zoom
|
# Defaults for the zoom level and center coordinates if the zoom
|
||||||
# is not automatically calculated.
|
# is not automatically calculated.
|
||||||
if zoom is None: zoom = 4
|
if zoom is None: zoom = 4
|
||||||
|
@ -105,6 +102,7 @@ class GoogleMap(object):
|
||||||
'zoom' : self.zoom,
|
'zoom' : self.zoom,
|
||||||
'polygons' : self.polygons,
|
'polygons' : self.polygons,
|
||||||
'polylines' : self.polylines,
|
'polylines' : self.polylines,
|
||||||
|
'icons': self.icons,
|
||||||
'markers' : self.markers,
|
'markers' : self.markers,
|
||||||
}
|
}
|
||||||
params.update(self.extra_context)
|
params.update(self.extra_context)
|
||||||
|
@ -174,7 +172,12 @@ class GoogleMapSet(GoogleMap):
|
||||||
self.maps = args[0]
|
self.maps = args[0]
|
||||||
else:
|
else:
|
||||||
self.maps = args
|
self.maps = args
|
||||||
|
|
||||||
|
# Creating the icons sequence from every map in this set.
|
||||||
|
self.icons = []
|
||||||
|
for map in self.maps:
|
||||||
|
self.icons.extend(map.icons)
|
||||||
|
|
||||||
# Generating DOM ids for each of the maps in the set.
|
# Generating DOM ids for each of the maps in the set.
|
||||||
self.dom_ids = ['map%d' % i for i in xrange(len(self.maps))]
|
self.dom_ids = ['map%d' % i for i in xrange(len(self.maps))]
|
||||||
|
|
||||||
|
@ -205,6 +208,7 @@ class GoogleMapSet(GoogleMap):
|
||||||
params = {'js_module' : self.js_module,
|
params = {'js_module' : self.js_module,
|
||||||
'dom_ids' : self.dom_ids,
|
'dom_ids' : self.dom_ids,
|
||||||
'load_map_js' : self.load_map_js(),
|
'load_map_js' : self.load_map_js(),
|
||||||
|
'icons' : self.icons,
|
||||||
}
|
}
|
||||||
params.update(self.extra_context)
|
params.update(self.extra_context)
|
||||||
return render_to_string(self.template, params)
|
return render_to_string(self.template, params)
|
||||||
|
|
|
@ -18,28 +18,28 @@ class GEvent(object):
|
||||||
|
|
||||||
def sample_request(request):
|
def sample_request(request):
|
||||||
polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)')
|
polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)')
|
||||||
event = GEvent('click',
|
event = GEvent('click',
|
||||||
'function() { location.href = "http://www.google.com"}')
|
'function() { location.href = "http://www.google.com"}')
|
||||||
polyline.add_event(event)
|
polyline.add_event(event)
|
||||||
return render_to_response('mytemplate.html',
|
return render_to_response('mytemplate.html',
|
||||||
{'google' : GoogleMap(polylines=[polyline])})
|
{'google' : GoogleMap(polylines=[polyline])})
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, event, action):
|
def __init__(self, event, action):
|
||||||
"""
|
"""
|
||||||
Initializes a GEvent object.
|
Initializes a GEvent object.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
event:
|
event:
|
||||||
string for the event, such as 'click'. The event must be a valid
|
string for the event, such as 'click'. The event must be a valid
|
||||||
event for the object in the Google Maps API.
|
event for the object in the Google Maps API.
|
||||||
There is no validation of the event type within Django.
|
There is no validation of the event type within Django.
|
||||||
|
|
||||||
action:
|
action:
|
||||||
string containing a Javascript function, such as
|
string containing a Javascript function, such as
|
||||||
'function() { location.href = "newurl";}'
|
'function() { location.href = "newurl";}'
|
||||||
The string must be a valid Javascript function. Again there is no
|
The string must be a valid Javascript function. Again there is no
|
||||||
validation fo the function within Django.
|
validation fo the function within Django.
|
||||||
"""
|
"""
|
||||||
self.event = event
|
self.event = event
|
||||||
|
@ -71,7 +71,7 @@ class GPolygon(GOverlayBase):
|
||||||
please see the Google Maps API Reference:
|
please see the Google Maps API Reference:
|
||||||
http://code.google.com/apis/maps/documentation/reference.html#GPolygon
|
http://code.google.com/apis/maps/documentation/reference.html#GPolygon
|
||||||
"""
|
"""
|
||||||
def __init__(self, poly,
|
def __init__(self, poly,
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
|
@ -98,25 +98,25 @@ class GPolygon(GOverlayBase):
|
||||||
"""
|
"""
|
||||||
if isinstance(poly, basestring): poly = fromstr(poly)
|
if isinstance(poly, basestring): poly = fromstr(poly)
|
||||||
if isinstance(poly, (tuple, list)): poly = Polygon(poly)
|
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.')
|
||||||
|
|
||||||
# Getting the envelope of the input polygon (used for automatically
|
# Getting the envelope of the input polygon (used for automatically
|
||||||
# determining the zoom level).
|
# determining the zoom level).
|
||||||
self.envelope = poly.envelope
|
self.envelope = poly.envelope
|
||||||
|
|
||||||
# Translating the coordinates into a JavaScript array of
|
# Translating the coordinates into a JavaScript array of
|
||||||
# Google `GLatLng` objects.
|
# Google `GLatLng` objects.
|
||||||
self.points = self.latlng_from_coords(poly.shell.coords)
|
self.points = self.latlng_from_coords(poly.shell.coords)
|
||||||
|
|
||||||
# Stroke settings.
|
# Stroke settings.
|
||||||
self.stroke_color, self.stroke_opacity, self.stroke_weight = stroke_color, stroke_opacity, stroke_weight
|
self.stroke_color, self.stroke_opacity, self.stroke_weight = stroke_color, stroke_opacity, stroke_weight
|
||||||
|
|
||||||
# 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__()
|
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,
|
||||||
|
@ -135,10 +135,10 @@ class GPolyline(GOverlayBase):
|
||||||
may instantiated into one of the above geometries.
|
may instantiated into one of the above geometries.
|
||||||
|
|
||||||
Keyword Options:
|
Keyword Options:
|
||||||
|
|
||||||
color:
|
color:
|
||||||
The color to use for the polyline. Defaults to '#0000ff' (blue).
|
The color to use for the polyline. Defaults to '#0000ff' (blue).
|
||||||
|
|
||||||
weight:
|
weight:
|
||||||
The width of the polyline, in pixels. Defaults to 2.
|
The width of the polyline, in pixels. Defaults to 2.
|
||||||
|
|
||||||
|
@ -160,11 +160,77 @@ class GPolyline(GOverlayBase):
|
||||||
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__()
|
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 GIcon(object):
|
||||||
|
"""
|
||||||
|
Creates a GIcon object to pass into a Gmarker object.
|
||||||
|
|
||||||
|
The keyword arguments map to instance attributes of the same name. These,
|
||||||
|
in turn, correspond to a subset of the attributes of the official GIcon
|
||||||
|
javascript object:
|
||||||
|
|
||||||
|
http://code.google.com/apis/maps/documentation/reference.html#GIcon
|
||||||
|
|
||||||
|
Because a Google map often uses several different icons, a name field has
|
||||||
|
been added to the required arguments.
|
||||||
|
|
||||||
|
Required Arguments:
|
||||||
|
varname:
|
||||||
|
A string which will become the basis for the js variable name of
|
||||||
|
the marker, for this reason, your code should assign a unique
|
||||||
|
name for each GIcon you instantiate, otherwise there will be
|
||||||
|
name space collisions in your javascript.
|
||||||
|
|
||||||
|
Keyword Options:
|
||||||
|
image:
|
||||||
|
The url of the image to be used as the icon on the map defaults
|
||||||
|
to 'G_DEFAULT_ICON'
|
||||||
|
|
||||||
|
iconsize:
|
||||||
|
a tuple representing the pixel size of the foreground (not the
|
||||||
|
shadow) image of the icon, in the format: (width, height) ex.:
|
||||||
|
|
||||||
|
GIcon('fast_food',
|
||||||
|
image="/media/icon/star.png",
|
||||||
|
iconsize=(15,10))
|
||||||
|
|
||||||
|
Would indicate your custom icon was 15px wide and 10px height.
|
||||||
|
|
||||||
|
shadow:
|
||||||
|
the url of the image of the icon's shadow
|
||||||
|
|
||||||
|
shadowsize:
|
||||||
|
a tuple representing the pixel size of the shadow image, format is
|
||||||
|
the same as ``iconsize``
|
||||||
|
|
||||||
|
iconanchor:
|
||||||
|
a tuple representing the pixel coordinate relative to the top left
|
||||||
|
corner of the icon image at which this icon is anchored to the map.
|
||||||
|
In (x, y) format. x increases to the right in the Google Maps
|
||||||
|
coordinate system and y increases downwards in the Google Maps
|
||||||
|
coordinate system.)
|
||||||
|
|
||||||
|
infowindowanchor:
|
||||||
|
The pixel coordinate relative to the top left corner of the icon
|
||||||
|
image at which the info window is anchored to this icon.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, varname, image=None, iconsize=None,
|
||||||
|
shadow=None, shadowsize=None, iconanchor=None,
|
||||||
|
infowindowanchor=None):
|
||||||
|
self.varname = varname
|
||||||
|
self.image = image
|
||||||
|
self.iconsize = iconsize
|
||||||
|
self.shadow = shadow
|
||||||
|
self.shadowsize = shadowsize
|
||||||
|
self.iconanchor = iconanchor
|
||||||
|
self.infowindowanchor = infowindowanchor
|
||||||
|
|
||||||
class GMarker(GOverlayBase):
|
class GMarker(GOverlayBase):
|
||||||
"""
|
"""
|
||||||
A Python wrapper for the Google GMarker object. For more information
|
A Python wrapper for the Google GMarker object. For more information
|
||||||
|
@ -175,25 +241,25 @@ class GMarker(GOverlayBase):
|
||||||
|
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.contrib.gis.maps.google.overlays import GMarker, GEvent
|
from django.contrib.gis.maps.google.overlays import GMarker, GEvent
|
||||||
|
|
||||||
def sample_request(request):
|
def sample_request(request):
|
||||||
marker = GMarker('POINT(101 26)')
|
marker = GMarker('POINT(101 26)')
|
||||||
event = GEvent('click',
|
event = GEvent('click',
|
||||||
'function() { location.href = "http://www.google.com"}')
|
'function() { location.href = "http://www.google.com"}')
|
||||||
marker.add_event(event)
|
marker.add_event(event)
|
||||||
return render_to_response('mytemplate.html',
|
return render_to_response('mytemplate.html',
|
||||||
{'google' : GoogleMap(markers=[marker])})
|
{'google' : GoogleMap(markers=[marker])})
|
||||||
"""
|
"""
|
||||||
def __init__(self, geom, title=None, draggable=False):
|
def __init__(self, geom, title=None, draggable=False, icon=None):
|
||||||
"""
|
"""
|
||||||
The GMarker object may initialize on GEOS Points or a parameter
|
The GMarker object may initialize on GEOS Points or a parameter
|
||||||
that may be instantiated into a GEOS point. Keyword options map to
|
that may be instantiated into a GEOS point. Keyword options map to
|
||||||
GMarkerOptions -- so far only the title option is supported.
|
GMarkerOptions -- so far only the title option is supported.
|
||||||
|
|
||||||
Keyword Options:
|
Keyword Options:
|
||||||
title:
|
title:
|
||||||
Title option for GMarker, will be displayed as a tooltip.
|
Title option for GMarker, will be displayed as a tooltip.
|
||||||
|
|
||||||
draggable:
|
draggable:
|
||||||
Draggable option for GMarker, disabled by default.
|
Draggable option for GMarker, disabled by default.
|
||||||
"""
|
"""
|
||||||
|
@ -209,15 +275,17 @@ class GMarker(GOverlayBase):
|
||||||
# TODO: Add support for more GMarkerOptions
|
# TODO: Add support for more GMarkerOptions
|
||||||
self.title = title
|
self.title = title
|
||||||
self.draggable = draggable
|
self.draggable = draggable
|
||||||
|
self.icon = icon
|
||||||
super(GMarker, self).__init__()
|
super(GMarker, self).__init__()
|
||||||
|
|
||||||
def latlng_from_coords(self, coords):
|
def latlng_from_coords(self, coords):
|
||||||
return 'new GLatLng(%s,%s)' %(coords[1], coords[0])
|
return 'new GLatLng(%s,%s)' %(coords[1], coords[0])
|
||||||
|
|
||||||
def options(self):
|
def options(self):
|
||||||
result = []
|
result = []
|
||||||
if self.title: result.append('title: "%s"' % self.title)
|
if self.title: result.append('title: "%s"' % self.title)
|
||||||
if self.draggable: result.append('draggable: true')
|
if self.icon: result.append('icon: %s' % self.icon.varname)
|
||||||
|
if self.draggable: result.append('draggable: true')
|
||||||
return '{%s}' % ','.join(result)
|
return '{%s}' % ','.join(result)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1,2 +1,7 @@
|
||||||
{% block vars %}var geodjango = {};{% endblock %}
|
{% block vars %}var geodjango = {};{% for icon in icons %}
|
||||||
|
var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON);
|
||||||
|
{% if icon.image %}{{ icon.varname }}.image = "{{ icon.image }}";{% endif %}
|
||||||
|
{% if icon.shadow %}{{ icon.varname }}.shadow = "{{ icon.shadow }}";{% endif %} {% if icon.shadowsize %}{{ icon.varname }}.shadowSize = new GSize({{ icon.shadowsize.0 }}, {{ icon.shadowsize.1 }});{% endif %}
|
||||||
|
{% if icon.iconanchor %}{{ icon.varname }}.iconAnchor = new GPoint({{ icon.iconanchor.0 }}, {{ icon.iconanchor.1 }});{% endif %} {% if icon.iconsize %}{{ icon.varname }}.iconSize = new GSize({{ icon.iconsize.0 }}, {{ icon.iconsize.1 }});{% endif %}
|
||||||
|
{% if icon.infowindowanchor %}{{ icon.varname }}.infoWindowAnchor = new GPoint({{ icon.infowindowanchor.0 }}, {{ icon.infowindowanchor.1 }});{% endif %}{% endfor %}{% endblock %}
|
||||||
{% block functions %}{% endblock %}
|
{% block functions %}{% endblock %}
|
Loading…
Reference in New Issue