|
0
|
1 |
from django.utils.safestring import mark_safe |
|
|
2 |
from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon |
|
|
3 |
|
|
|
4 |
class GEvent(object): |
|
|
5 |
""" |
|
|
6 |
A Python wrapper for the Google GEvent object. |
|
|
7 |
|
|
|
8 |
Events can be attached to any object derived from GOverlayBase with the |
|
|
9 |
add_event() call. |
|
|
10 |
|
|
|
11 |
For more information please see the Google Maps API Reference: |
|
|
12 |
http://code.google.com/apis/maps/documentation/reference.html#GEvent |
|
|
13 |
|
|
|
14 |
Example: |
|
|
15 |
|
|
|
16 |
from django.shortcuts import render_to_response |
|
|
17 |
from django.contrib.gis.maps.google import GoogleMap, GEvent, GPolyline |
|
|
18 |
|
|
|
19 |
def sample_request(request): |
|
|
20 |
polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)') |
|
|
21 |
event = GEvent('click', |
|
|
22 |
'function() { location.href = "http://www.google.com"}') |
|
|
23 |
polyline.add_event(event) |
|
|
24 |
return render_to_response('mytemplate.html', |
|
|
25 |
{'google' : GoogleMap(polylines=[polyline])}) |
|
|
26 |
""" |
|
|
27 |
|
|
|
28 |
def __init__(self, event, action): |
|
|
29 |
""" |
|
|
30 |
Initializes a GEvent object. |
|
|
31 |
|
|
|
32 |
Parameters: |
|
|
33 |
|
|
|
34 |
event: |
|
|
35 |
string for the event, such as 'click'. The event must be a valid |
|
|
36 |
event for the object in the Google Maps API. |
|
|
37 |
There is no validation of the event type within Django. |
|
|
38 |
|
|
|
39 |
action: |
|
|
40 |
string containing a Javascript function, such as |
|
|
41 |
'function() { location.href = "newurl";}' |
|
|
42 |
The string must be a valid Javascript function. Again there is no |
|
|
43 |
validation fo the function within Django. |
|
|
44 |
""" |
|
|
45 |
self.event = event |
|
|
46 |
self.action = action |
|
|
47 |
|
|
|
48 |
def __unicode__(self): |
|
|
49 |
"Returns the parameter part of a GEvent." |
|
|
50 |
return mark_safe('"%s", %s' %(self.event, self.action)) |
|
|
51 |
|
|
|
52 |
class GOverlayBase(object): |
|
|
53 |
def __init__(self): |
|
|
54 |
self.events = [] |
|
|
55 |
|
|
|
56 |
def latlng_from_coords(self, coords): |
|
|
57 |
"Generates a JavaScript array of GLatLng objects for the given coordinates." |
|
|
58 |
return '[%s]' % ','.join(['new GLatLng(%s,%s)' % (y, x) for x, y in coords]) |
|
|
59 |
|
|
|
60 |
def add_event(self, event): |
|
|
61 |
"Attaches a GEvent to the overlay object." |
|
|
62 |
self.events.append(event) |
|
|
63 |
|
|
|
64 |
def __unicode__(self): |
|
|
65 |
"The string representation is the JavaScript API call." |
|
|
66 |
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params)) |
|
|
67 |
|
|
|
68 |
class GPolygon(GOverlayBase): |
|
|
69 |
""" |
|
|
70 |
A Python wrapper for the Google GPolygon object. For more information |
|
|
71 |
please see the Google Maps API Reference: |
|
|
72 |
http://code.google.com/apis/maps/documentation/reference.html#GPolygon |
|
|
73 |
""" |
|
|
74 |
def __init__(self, poly, |
|
|
75 |
stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1, |
|
|
76 |
fill_color='#0000ff', fill_opacity=0.4): |
|
|
77 |
""" |
|
|
78 |
The GPolygon object initializes on a GEOS Polygon or a parameter that |
|
|
79 |
may be instantiated into GEOS Polygon. Please note that this will not |
|
|
80 |
depict a Polygon's internal rings. |
|
|
81 |
|
|
|
82 |
Keyword Options: |
|
|
83 |
|
|
|
84 |
stroke_color: |
|
|
85 |
The color of the polygon outline. Defaults to '#0000ff' (blue). |
|
|
86 |
|
|
|
87 |
stroke_weight: |
|
|
88 |
The width of the polygon outline, in pixels. Defaults to 2. |
|
|
89 |
|
|
|
90 |
stroke_opacity: |
|
|
91 |
The opacity of the polygon outline, between 0 and 1. Defaults to 1. |
|
|
92 |
|
|
|
93 |
fill_color: |
|
|
94 |
The color of the polygon fill. Defaults to '#0000ff' (blue). |
|
|
95 |
|
|
|
96 |
fill_opacity: |
|
|
97 |
The opacity of the polygon fill. Defaults to 0.4. |
|
|
98 |
""" |
|
|
99 |
if isinstance(poly, basestring): poly = fromstr(poly) |
|
|
100 |
if isinstance(poly, (tuple, list)): poly = Polygon(poly) |
|
|
101 |
if not isinstance(poly, Polygon): |
|
|
102 |
raise TypeError('GPolygon may only initialize on GEOS Polygons.') |
|
|
103 |
|
|
|
104 |
# Getting the envelope of the input polygon (used for automatically |
|
|
105 |
# determining the zoom level). |
|
|
106 |
self.envelope = poly.envelope |
|
|
107 |
|
|
|
108 |
# Translating the coordinates into a JavaScript array of |
|
|
109 |
# Google `GLatLng` objects. |
|
|
110 |
self.points = self.latlng_from_coords(poly.shell.coords) |
|
|
111 |
|
|
|
112 |
# Stroke settings. |
|
|
113 |
self.stroke_color, self.stroke_opacity, self.stroke_weight = stroke_color, stroke_opacity, stroke_weight |
|
|
114 |
|
|
|
115 |
# Fill settings. |
|
|
116 |
self.fill_color, self.fill_opacity = fill_color, fill_opacity |
|
|
117 |
|
|
|
118 |
super(GPolygon, self).__init__() |
|
|
119 |
|
|
|
120 |
@property |
|
|
121 |
def js_params(self): |
|
|
122 |
return '%s, "%s", %s, %s, "%s", %s' % (self.points, self.stroke_color, self.stroke_weight, self.stroke_opacity, |
|
|
123 |
self.fill_color, self.fill_opacity) |
|
|
124 |
|
|
|
125 |
class GPolyline(GOverlayBase): |
|
|
126 |
""" |
|
|
127 |
A Python wrapper for the Google GPolyline object. For more information |
|
|
128 |
please see the Google Maps API Reference: |
|
|
129 |
http://code.google.com/apis/maps/documentation/reference.html#GPolyline |
|
|
130 |
""" |
|
|
131 |
def __init__(self, geom, color='#0000ff', weight=2, opacity=1): |
|
|
132 |
""" |
|
|
133 |
The GPolyline object may be initialized on GEOS LineStirng, LinearRing, |
|
|
134 |
and Polygon objects (internal rings not supported) or a parameter that |
|
|
135 |
may instantiated into one of the above geometries. |
|
|
136 |
|
|
|
137 |
Keyword Options: |
|
|
138 |
|
|
|
139 |
color: |
|
|
140 |
The color to use for the polyline. Defaults to '#0000ff' (blue). |
|
|
141 |
|
|
|
142 |
weight: |
|
|
143 |
The width of the polyline, in pixels. Defaults to 2. |
|
|
144 |
|
|
|
145 |
opacity: |
|
|
146 |
The opacity of the polyline, between 0 and 1. Defaults to 1. |
|
|
147 |
""" |
|
|
148 |
# If a GEOS geometry isn't passed in, try to contsruct one. |
|
|
149 |
if isinstance(geom, basestring): geom = fromstr(geom) |
|
|
150 |
if isinstance(geom, (tuple, list)): geom = Polygon(geom) |
|
|
151 |
# Generating the lat/lng coordinate pairs. |
|
|
152 |
if isinstance(geom, (LineString, LinearRing)): |
|
|
153 |
self.latlngs = self.latlng_from_coords(geom.coords) |
|
|
154 |
elif isinstance(geom, Polygon): |
|
|
155 |
self.latlngs = self.latlng_from_coords(geom.shell.coords) |
|
|
156 |
else: |
|
|
157 |
raise TypeError('GPolyline may only initialize on GEOS LineString, LinearRing, and/or Polygon geometries.') |
|
|
158 |
|
|
|
159 |
# Getting the envelope for automatic zoom determination. |
|
|
160 |
self.envelope = geom.envelope |
|
|
161 |
self.color, self.weight, self.opacity = color, weight, opacity |
|
|
162 |
super(GPolyline, self).__init__() |
|
|
163 |
|
|
|
164 |
@property |
|
|
165 |
def js_params(self): |
|
|
166 |
return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity) |
|
|
167 |
|
|
|
168 |
|
|
|
169 |
class GIcon(object): |
|
|
170 |
""" |
|
|
171 |
Creates a GIcon object to pass into a Gmarker object. |
|
|
172 |
|
|
|
173 |
The keyword arguments map to instance attributes of the same name. These, |
|
|
174 |
in turn, correspond to a subset of the attributes of the official GIcon |
|
|
175 |
javascript object: |
|
|
176 |
|
|
|
177 |
http://code.google.com/apis/maps/documentation/reference.html#GIcon |
|
|
178 |
|
|
|
179 |
Because a Google map often uses several different icons, a name field has |
|
|
180 |
been added to the required arguments. |
|
|
181 |
|
|
|
182 |
Required Arguments: |
|
|
183 |
varname: |
|
|
184 |
A string which will become the basis for the js variable name of |
|
|
185 |
the marker, for this reason, your code should assign a unique |
|
|
186 |
name for each GIcon you instantiate, otherwise there will be |
|
|
187 |
name space collisions in your javascript. |
|
|
188 |
|
|
|
189 |
Keyword Options: |
|
|
190 |
image: |
|
|
191 |
The url of the image to be used as the icon on the map defaults |
|
|
192 |
to 'G_DEFAULT_ICON' |
|
|
193 |
|
|
|
194 |
iconsize: |
|
|
195 |
a tuple representing the pixel size of the foreground (not the |
|
|
196 |
shadow) image of the icon, in the format: (width, height) ex.: |
|
|
197 |
|
|
|
198 |
GIcon('fast_food', |
|
|
199 |
image="/media/icon/star.png", |
|
|
200 |
iconsize=(15,10)) |
|
|
201 |
|
|
|
202 |
Would indicate your custom icon was 15px wide and 10px height. |
|
|
203 |
|
|
|
204 |
shadow: |
|
|
205 |
the url of the image of the icon's shadow |
|
|
206 |
|
|
|
207 |
shadowsize: |
|
|
208 |
a tuple representing the pixel size of the shadow image, format is |
|
|
209 |
the same as ``iconsize`` |
|
|
210 |
|
|
|
211 |
iconanchor: |
|
|
212 |
a tuple representing the pixel coordinate relative to the top left |
|
|
213 |
corner of the icon image at which this icon is anchored to the map. |
|
|
214 |
In (x, y) format. x increases to the right in the Google Maps |
|
|
215 |
coordinate system and y increases downwards in the Google Maps |
|
|
216 |
coordinate system.) |
|
|
217 |
|
|
|
218 |
infowindowanchor: |
|
|
219 |
The pixel coordinate relative to the top left corner of the icon |
|
|
220 |
image at which the info window is anchored to this icon. |
|
|
221 |
|
|
|
222 |
""" |
|
|
223 |
def __init__(self, varname, image=None, iconsize=None, |
|
|
224 |
shadow=None, shadowsize=None, iconanchor=None, |
|
|
225 |
infowindowanchor=None): |
|
|
226 |
self.varname = varname |
|
|
227 |
self.image = image |
|
|
228 |
self.iconsize = iconsize |
|
|
229 |
self.shadow = shadow |
|
|
230 |
self.shadowsize = shadowsize |
|
|
231 |
self.iconanchor = iconanchor |
|
|
232 |
self.infowindowanchor = infowindowanchor |
|
|
233 |
|
|
|
234 |
def __cmp__(self, other): |
|
|
235 |
return cmp(self.varname, other.varname) |
|
|
236 |
|
|
|
237 |
def __hash__(self): |
|
|
238 |
# XOR with hash of GIcon type so that hash('varname') won't |
|
|
239 |
# equal hash(GIcon('varname')). |
|
|
240 |
return hash(self.__class__) ^ hash(self.varname) |
|
|
241 |
|
|
|
242 |
class GMarker(GOverlayBase): |
|
|
243 |
""" |
|
|
244 |
A Python wrapper for the Google GMarker object. For more information |
|
|
245 |
please see the Google Maps API Reference: |
|
|
246 |
http://code.google.com/apis/maps/documentation/reference.html#GMarker |
|
|
247 |
|
|
|
248 |
Example: |
|
|
249 |
|
|
|
250 |
from django.shortcuts import render_to_response |
|
|
251 |
from django.contrib.gis.maps.google.overlays import GMarker, GEvent |
|
|
252 |
|
|
|
253 |
def sample_request(request): |
|
|
254 |
marker = GMarker('POINT(101 26)') |
|
|
255 |
event = GEvent('click', |
|
|
256 |
'function() { location.href = "http://www.google.com"}') |
|
|
257 |
marker.add_event(event) |
|
|
258 |
return render_to_response('mytemplate.html', |
|
|
259 |
{'google' : GoogleMap(markers=[marker])}) |
|
|
260 |
""" |
|
|
261 |
def __init__(self, geom, title=None, draggable=False, icon=None): |
|
|
262 |
""" |
|
|
263 |
The GMarker object may initialize on GEOS Points or a parameter |
|
|
264 |
that may be instantiated into a GEOS point. Keyword options map to |
|
|
265 |
GMarkerOptions -- so far only the title option is supported. |
|
|
266 |
|
|
|
267 |
Keyword Options: |
|
|
268 |
title: |
|
|
269 |
Title option for GMarker, will be displayed as a tooltip. |
|
|
270 |
|
|
|
271 |
draggable: |
|
|
272 |
Draggable option for GMarker, disabled by default. |
|
|
273 |
""" |
|
|
274 |
# If a GEOS geometry isn't passed in, try to construct one. |
|
|
275 |
if isinstance(geom, basestring): geom = fromstr(geom) |
|
|
276 |
if isinstance(geom, (tuple, list)): geom = Point(geom) |
|
|
277 |
if isinstance(geom, Point): |
|
|
278 |
self.latlng = self.latlng_from_coords(geom.coords) |
|
|
279 |
else: |
|
|
280 |
raise TypeError('GMarker may only initialize on GEOS Point geometry.') |
|
|
281 |
# Getting the envelope for automatic zoom determination. |
|
|
282 |
self.envelope = geom.envelope |
|
|
283 |
# TODO: Add support for more GMarkerOptions |
|
|
284 |
self.title = title |
|
|
285 |
self.draggable = draggable |
|
|
286 |
self.icon = icon |
|
|
287 |
super(GMarker, self).__init__() |
|
|
288 |
|
|
|
289 |
def latlng_from_coords(self, coords): |
|
|
290 |
return 'new GLatLng(%s,%s)' %(coords[1], coords[0]) |
|
|
291 |
|
|
|
292 |
def options(self): |
|
|
293 |
result = [] |
|
|
294 |
if self.title: result.append('title: "%s"' % self.title) |
|
|
295 |
if self.icon: result.append('icon: %s' % self.icon.varname) |
|
|
296 |
if self.draggable: result.append('draggable: true') |
|
|
297 |
return '{%s}' % ','.join(result) |
|
|
298 |
|
|
|
299 |
@property |
|
|
300 |
def js_params(self): |
|
|
301 |
return '%s, %s' % (self.latlng, self.options()) |