PageRenderTime 51ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 1ms

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

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