Django

Code

root/django/trunk/django/contrib/gis/maps/google/gmap.py

Revision 11124, 8.8 kB (checked in by jbronn, 5 days ago)

Fixed #11249, #11261 -- Blocks may now be overridden again google-map.js template; now use GMaps setUIToDefault to use default controls. Thanks to ludifan and Peter Landry for the ttickets and patch.

Line 
1 from django.conf import settings
2 from django.contrib.gis import geos
3 from django.template.loader import render_to_string
4 from django.utils.safestring import mark_safe
5
6 class GoogleMapException(Exception): pass
7 from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker, GIcon
8
9 # The default Google Maps URL (for the API javascript)
10 # TODO: Internationalize for Japan, UK, etc.
11 GOOGLE_MAPS_URL='http://maps.google.com/maps?file=api&v=%s&key='
12
13 class GoogleMap(object):
14     "A class for generating Google Maps JavaScript."
15
16     # String constants
17     onunload = mark_safe('onunload="GUnload()"') # Cleans up after Google Maps
18     vml_css  = mark_safe('v\:* {behavior:url(#default#VML);}') # CSS for IE VML
19     xmlns    = mark_safe('xmlns:v="urn:schemas-microsoft-com:vml"') # XML Namespace (for IE VML).
20
21     def __init__(self, key=None, api_url=None, version=None,
22                  center=None, zoom=None, dom_id='map',
23                  kml_urls=[], polylines=None, polygons=None, markers=None,
24                  template='gis/google/google-map.js',
25                  js_module='geodjango',
26                  extra_context={}):
27
28         # The Google Maps API Key defined in the settings will be used
29         # if not passed in as a parameter.  The use of an API key is
30         # _required_.
31         if not key:
32             try:
33                 self.key = settings.GOOGLE_MAPS_API_KEY
34             except AttributeError:
35                 raise GoogleMapException('Google Maps API Key not found (try adding GOOGLE_MAPS_API_KEY to your settings).')
36         else:
37             self.key = key
38
39         # Getting the Google Maps API version, defaults to using the latest ("2.x"),
40         # this is not necessarily the most stable.
41         if not version:
42             self.version = getattr(settings, 'GOOGLE_MAPS_API_VERSION', '2.x')
43         else:
44             self.version = version
45
46         # Can specify the API URL in the `api_url` keyword.
47         if not api_url:
48             self.api_url = mark_safe(getattr(settings, 'GOOGLE_MAPS_URL', GOOGLE_MAPS_URL) % self.version)
49         else:
50             self.api_url = api_url
51
52         # Setting the DOM id of the map, the load function, the JavaScript
53         # template, and the KML URLs array.
54         self.dom_id = dom_id
55         self.extra_context = extra_context
56         self.js_module = js_module
57         self.template = template
58         self.kml_urls = kml_urls
59
60         # Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
61         overlay_info = [[GMarker, markers, 'markers'],
62                         [GPolygon, polygons, 'polygons'],
63                         [GPolyline, polylines, 'polylines']]
64
65         for overlay_class, overlay_list, varname in overlay_info:
66             setattr(self, varname, [])
67             if overlay_list:
68                 for overlay in overlay_list:
69                     if isinstance(overlay, overlay_class):
70                         getattr(self, varname).append(overlay)
71                     else:
72                         getattr(self, varname).append(overlay_class(overlay))
73
74         # If GMarker, GPolygons, and/or GPolylines are used the zoom will be
75         # automatically calculated via the Google Maps API.  If both a zoom
76         # level and a center coordinate are provided with polygons/polylines,
77         # no automatic determination will occur.
78         self.calc_zoom = False
79         if self.polygons or self.polylines  or self.markers:
80             if center is None or zoom is None:
81                 self.calc_zoom = True
82
83         # Defaults for the zoom level and center coordinates if the zoom
84         # is not automatically calculated.
85         if zoom is None: zoom = 4
86         self.zoom = zoom
87         if center is None: center = (0, 0)
88         self.center = center
89
90     def render(self):
91         """
92         Generates the JavaScript necessary for displaying this Google Map.
93         """
94         params = {'calc_zoom' : self.calc_zoom,
95                   'center' : self.center,
96                   'dom_id' : self.dom_id,
97                   'js_module' : self.js_module,
98                   'kml_urls' : self.kml_urls,
99                   'zoom' : self.zoom,
100                   'polygons' : self.polygons,
101                   'polylines' : self.polylines,
102                   'icons': self.icons,
103                   'markers' : self.markers,
104                   }
105         params.update(self.extra_context)
106         return render_to_string(self.template, params)
107
108     @property
109     def body(self):
110         "Returns HTML body tag for loading and unloading Google Maps javascript."
111         return mark_safe('<body %s %s>' % (self.onload, self.onunload))
112
113     @property
114     def onload(self):
115         "Returns the `onload` HTML <body> attribute."
116         return mark_safe('onload="%s.%s_load()"' % (self.js_module, self.dom_id))
117
118     @property
119     def api_script(self):
120         "Returns the <script> tag for the Google Maps API javascript."
121         return mark_safe('<script src="%s%s" type="text/javascript"></script>' % (self.api_url, self.key))
122
123     @property
124     def js(self):
125         "Returns only the generated Google Maps JavaScript (no <script> tags)."
126         return self.render()
127
128     @property
129     def scripts(self):
130         "Returns all <script></script> tags required with Google Maps JavaScript."
131         return mark_safe('%s\n  <script type="text/javascript">\n//<![CDATA[\n%s//]]>\n  </script>' % (self.api_script, self.js))
132
133     @property
134     def style(self):
135         "Returns additional CSS styling needed for Google Maps on IE."
136         return mark_safe('<style type="text/css">%s</style>' % self.vml_css)
137
138     @property
139     def xhtml(self):
140         "Returns XHTML information needed for IE VML overlays."
141         return mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" %s>' % self.xmlns)
142
143     @property
144     def icons(self):
145         "Returns a sequence of GIcon objects in this map."
146         return set([marker.icon for marker in self.markers if marker.icon])
147
148 class GoogleMapSet(GoogleMap):
149
150     def __init__(self, *args, **kwargs):
151         """
152         A class for generating sets of Google Maps that will be shown on the
153         same page together.
154
155         Example:
156          gmapset = GoogleMapSet( GoogleMap( ... ), GoogleMap( ... ) )
157          gmapset = GoogleMapSet( [ gmap1, gmap2] )
158         """
159         # The `google-multi.js` template is used instead of `google-single.js`
160         # by default.
161         template = kwargs.pop('template', 'gis/google/google-multi.js')
162
163         # This is the template used to generate the GMap load JavaScript for
164         # each map in the set.
165         self.map_template = kwargs.pop('map_template', 'gis/google/google-single.js')
166
167         # Running GoogleMap.__init__(), and resetting the template
168         # value with default obtained above.
169         super(GoogleMapSet, self).__init__(**kwargs)
170         self.template = template
171
172         # If a tuple/list passed in as first element of args, then assume
173         if isinstance(args[0], (tuple, list)):
174             self.maps = args[0]
175         else:
176             self.maps = args
177
178         # Generating DOM ids for each of the maps in the set.
179         self.dom_ids = ['map%d' % i for i in xrange(len(self.maps))]
180
181     def load_map_js(self):
182         """
183         Returns JavaScript containing all of the loading routines for each
184         map in this set.
185         """
186         result = []
187         for dom_id, gmap in zip(self.dom_ids, self.maps):
188             # Backup copies the GoogleMap DOM id and template attributes.
189             # They are overridden on each GoogleMap instance in the set so
190             # that only the loading JavaScript (and not the header variables)
191             # is used with the generated DOM ids.
192             tmp = (gmap.template, gmap.dom_id)
193             gmap.template = self.map_template
194             gmap.dom_id = dom_id
195             result.append(gmap.js)
196             # Restoring the backup values.
197             gmap.template, gmap.dom_id = tmp
198         return mark_safe(''.join(result))
199
200     def render(self):
201         """
202         Generates the JavaScript for the collection of Google Maps in
203         this set.
204         """
205         params = {'js_module' : self.js_module,
206                   'dom_ids' : self.dom_ids,
207                   'load_map_js' : self.load_map_js(),
208                   'icons' : self.icons,
209                   }
210         params.update(self.extra_context)
211         return render_to_string(self.template, params)
212
213     @property
214     def onload(self):
215         "Returns the `onload` HTML <body> attribute."
216         # Overloaded to use the `load` function defined in the
217         # `google-multi.js`, which calls the load routines for
218         # each one of the individual maps in the set.
219         return mark_safe('onload="%s.load()"' % self.js_module)
220
221     @property
222     def icons(self):
223         "Returns a sequence of all icons in each map of the set."
224         icons = set()
225         for map in self.maps: icons |= map.icons
226         return icons
Note: See TracBrowser for help on using the browser.