From d45e24a1f849e1f244b58565223765c95156fef1 Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Mon, 9 Mar 2009 19:22:24 +0000 Subject: [PATCH] Fixed #9955 -- Added `GoogleMapSet`, which enables multiple `GoogleMap` objects to placed on the same page; moved all templates to `google` parent dir, and added 'google-map.html' for an included example. Thanks to mandric for the ticket and aromano for initial patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@10011 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/gis/maps/google/__init__.py | 2 +- django/contrib/gis/maps/google/gmap.py | 116 +++++++++++++++--- .../gis/templates/gis/google/google-base.js | 2 + .../gis/templates/gis/google/google-map.html | 12 ++ .../gis/templates/gis/google/google-map.js | 29 +++++ .../gis/templates/gis/google/google-multi.js | 8 ++ .../gis/templates/gis/google/google-single.js | 2 + .../gis/templates/gis/google/js/google-map.js | 34 ----- 8 files changed, 152 insertions(+), 53 deletions(-) create mode 100644 django/contrib/gis/templates/gis/google/google-base.js create mode 100644 django/contrib/gis/templates/gis/google/google-map.html create mode 100644 django/contrib/gis/templates/gis/google/google-map.js create mode 100644 django/contrib/gis/templates/gis/google/google-multi.js create mode 100644 django/contrib/gis/templates/gis/google/google-single.js delete mode 100644 django/contrib/gis/templates/gis/google/js/google-map.js diff --git a/django/contrib/gis/maps/google/__init__.py b/django/contrib/gis/maps/google/__init__.py index dfbbedc3d6..351962d05b 100644 --- a/django/contrib/gis/maps/google/__init__.py +++ b/django/contrib/gis/maps/google/__init__.py @@ -56,6 +56,6 @@ * GOOGLE_MAPS_URL (optional): Must have a substitution ('%s') for the API version. """ -from django.contrib.gis.maps.google.gmap import GoogleMap +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.zoom import GoogleZoom diff --git a/django/contrib/gis/maps/google/gmap.py b/django/contrib/gis/maps/google/gmap.py index 580ab7ad8e..87734af5fc 100644 --- a/django/contrib/gis/maps/google/gmap.py +++ b/django/contrib/gis/maps/google/gmap.py @@ -19,14 +19,14 @@ class GoogleMap(object): 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, - center=None, zoom=None, dom_id='map', load_func='gmap_load', + center=None, zoom=None, dom_id='map', kml_urls=[], polygons=[], polylines=[], markers=[], - template='gis/google/js/google-map.js', - extra_context={}): + template='gis/google/google-single.js', + js_module='geodjango',extra_context={}): # 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 - # _required_. + # if not passed in as a parameter. The use of an API key is + # _required_. if not key: try: self.key = settings.GOOGLE_MAPS_API_KEY @@ -36,7 +36,7 @@ class GoogleMap(object): self.key = key # 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: self.version = getattr(settings, 'GOOGLE_MAPS_API_VERSION', '2.x') else: @@ -51,7 +51,8 @@ class GoogleMap(object): # Setting the DOM id of the map, the load function, the JavaScript # template, and the KML URLs array. self.dom_id = dom_id - self.load_func = load_func + self.extra_context = extra_context + self.js_module = js_module self.template = template self.kml_urls = kml_urls @@ -76,11 +77,10 @@ class GoogleMap(object): else: self.polylines.append(GPolyline(pline)) - # 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 - # center coordinate are provided with polygons/polylines, no automatic - # determination will occur. + # 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 center coordinate are provided with polygons/polylines, + # no automatic determination will occur. self.calc_zoom = False if self.polygons or self.polylines or self.markers: if center is None or zoom is None: @@ -93,19 +93,22 @@ class GoogleMap(object): if center is None: center = (0, 0) self.center = center - # Setting the parameters for the javascript template. + def render(self): + """ + Generates the JavaScript necessary for displaying this Google Map. + """ params = {'calc_zoom' : self.calc_zoom, 'center' : self.center, 'dom_id' : self.dom_id, + 'js_module' : self.js_module, 'kml_urls' : self.kml_urls, - 'load_func' : self.load_func, 'zoom' : self.zoom, 'polygons' : self.polygons, 'polylines' : self.polylines, 'markers' : self.markers, } - params.update(extra_context) - self.js = render_to_string(self.template, params) + params.update(self.extra_context) + return render_to_string(self.template, params) @property def body(self): @@ -115,16 +118,21 @@ class GoogleMap(object): @property def onload(self): "Returns the `onload` HTML attribute." - return mark_safe('onload="%s()"' % self.load_func) + return mark_safe('onload="%s.%s_load()"' % (self.js_module, self.dom_id)) @property def api_script(self): "Returns the ' % (self.api_url, self.key)) + @property + def js(self): + "Returns only the generated Google Maps JavaScript (no tags required for Google Maps JavaScript." + "Returns all tags required with Google Maps JavaScript." return mark_safe('%s\n ' % (self.api_script, self.js)) @property @@ -136,3 +144,75 @@ class GoogleMap(object): def xhtml(self): "Returns XHTML information needed for IE VML overlays." return mark_safe('' % self.xmlns) + +class GoogleMapSet(GoogleMap): + + def __init__(self, *args, **kwargs): + """ + A class for generating sets of Google Maps that will be shown on the + same page together. + + Example: + gmapset = GoogleMapSet( GoogleMap( ... ), GoogleMap( ... ) ) + gmapset = GoogleMapSet( [ gmap1, gmap2] ) + """ + # The `google-multi.js` template is used instead of `google-single.js` + # by default. + template = kwargs.pop('template', 'gis/google/google-multi.js') + + # This is the template used to generate the GMap load JavaScript for + # each map in the set. + self.map_template = kwargs.pop('map_template', 'gis/google/google-map.js') + + # Running GoogleMap.__init__(), and resetting the template + # value with default obtained above. + super(GoogleMapSet, self).__init__(**kwargs) + self.template = template + + # If a tuple/list passed in as first element of args, then assume + if isinstance(args[0], (tuple, list)): + self.maps = args[0] + else: + self.maps = args + + # Generating DOM ids for each of the maps in the set. + self.dom_ids = ['map%d' % i for i in xrange(len(self.maps))] + + def load_map_js(self): + """ + Returns JavaScript containing all of the loading routines for each + map in this set. + """ + result = [] + for dom_id, gmap in zip(self.dom_ids, self.maps): + # Backup copies the GoogleMap DOM id and template attributes. + # They are overridden on each GoogleMap instance in the set so + # that only the loading JavaScript (and not the header variables) + # is used with the generated DOM ids. + tmp = (gmap.template, gmap.dom_id) + gmap.template = self.map_template + gmap.dom_id = dom_id + result.append(gmap.js) + # Restoring the backup values. + gmap.template, gmap.dom_id = tmp + return mark_safe(''.join(result)) + + def render(self): + """ + Generates the JavaScript for the collection of Google Maps in + this set. + """ + params = {'js_module' : self.js_module, + 'dom_ids' : self.dom_ids, + 'load_map_js' : self.load_map_js(), + } + params.update(self.extra_context) + return render_to_string(self.template, params) + + @property + def onload(self): + "Returns the `onload` HTML attribute." + # Overloaded to use the `load` function defined in the + # `google-multi.js`, which calls the load routines for + # each one of the individual maps in the set. + return mark_safe('onload="%s.load()"' % self.js_module) diff --git a/django/contrib/gis/templates/gis/google/google-base.js b/django/contrib/gis/templates/gis/google/google-base.js new file mode 100644 index 0000000000..3fee82242f --- /dev/null +++ b/django/contrib/gis/templates/gis/google/google-base.js @@ -0,0 +1,2 @@ +{% block vars %}var geodjango = {};{% endblock %} +{% block functions %}{% endblock %} \ No newline at end of file diff --git a/django/contrib/gis/templates/gis/google/google-map.html b/django/contrib/gis/templates/gis/google/google-map.html new file mode 100644 index 0000000000..fb60e44fba --- /dev/null +++ b/django/contrib/gis/templates/gis/google/google-map.html @@ -0,0 +1,12 @@ + + + + {% block title %}Google Maps via GeoDjango{% endblock %} + {{ gmap.style }} + {{ gmap.scripts }} + + +{% if gmap.dom_ids %}{% for dom_id in gmap.dom_ids %}
{% endfor %} +{% else %}
{% endif %} + + diff --git a/django/contrib/gis/templates/gis/google/google-map.js b/django/contrib/gis/templates/gis/google/google-map.js new file mode 100644 index 0000000000..e5f3a0e0e3 --- /dev/null +++ b/django/contrib/gis/templates/gis/google/google-map.js @@ -0,0 +1,29 @@ +{% autoescape off %} +{% block load %}{{ js_module }}.{{ dom_id }}_load = function(){ + if (GBrowserIsCompatible()) { + {{ js_module }}.{{ dom_id }} = new GMap2(document.getElementById("{{ dom_id }}")); + {{ js_module }}.{{ dom_id }}.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }}); + {% block controls %}{{ js_module }}.{{ dom_id }}.addControl(new GSmallMapControl()); + {{ js_module }}.{{ dom_id }}.addControl(new GMapTypeControl());{% endblock %} + {% if calc_zoom %}var bounds = new GLatLngBounds(); var tmp_bounds = new GLatLngBounds();{% endif %} + {% for kml_url in kml_urls %}{{ js_module }}.{{ dom_id }}_kml{{ forloop.counter }} = new GGeoXml("{{ kml_url }}"); + {{ js_module }}.{{ dom_id }}.addOverlay({{ js_module }}.{{ dom_id }}_kml{{ forloop.counter }});{% endfor %} + {% for polygon in polygons %}{{ js_module }}.{{ dom_id }}_poly{{ forloop.counter }} = new {{ polygon }}; + {{ js_module }}.{{ dom_id }}.addOverlay({{ js_module }}.{{ dom_id }}_poly{{ forloop.counter }}); + {% for event in polygon.events %}GEvent.addListener({{ js_module }}.{{ dom_id }}_poly{{ forloop.parentloop.counter }}, {{ event }});{% endfor %} + {% if calc_zoom %}tmp_bounds = {{ js_module }}.{{ dom_id }}_poly{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %} + {% for polyline in polylines %}{{ js_module }}.{{ dom_id }}_polyline{{ forloop.counter }} = new {{ polyline }}; + {{ js_module }}.{{ dom_id }}.addOverlay({{ js_module }}.{{ dom_id }}_polyline{{ forloop.counter }}); + {% for event in polyline.events %}GEvent.addListener({{ js_module }}.{{ dom_id }}_polyline{{ forloop.parentloop.counter }}, {{ event }}); {% endfor %} + {% if calc_zoom %}tmp_bounds = {{ js_module }}.{{ dom_id }}_polyline{{ forloop.counter }}.getBounds(); bounds.extend(tmp_bounds.getSouthWest()); bounds.extend(tmp_bounds.getNorthEast());{% endif %}{% endfor %} + {% for marker in markers %}{{ js_module }}.{{ dom_id }}_marker{{ forloop.counter }} = new {{ marker }}; + {{ js_module }}.{{ dom_id }}.addOverlay({{ js_module }}.{{ dom_id }}_marker{{ forloop.counter }}); + {% for event in marker.events %}GEvent.addListener({{ js_module }}.{{ dom_id }}_marker{{ forloop.parentloop.counter }}, {{ event }}); {% endfor %} + {% if calc_zoom %}bounds.extend({{ js_module }}.{{ dom_id }}_marker{{ forloop.counter }}.getLatLng()); {% endif %}{% endfor %} + {% if calc_zoom %}{{ js_module }}.{{ dom_id }}.setCenter(bounds.getCenter(), {{ js_module }}.{{ dom_id }}.getBoundsZoomLevel(bounds));{% endif %} + {% block load_extra %}{% endblock %} + }else { + alert("Sorry, the Google Maps API is not compatible with this browser."); + } +} +{% endblock %}{% endautoescape %} diff --git a/django/contrib/gis/templates/gis/google/google-multi.js b/django/contrib/gis/templates/gis/google/google-multi.js new file mode 100644 index 0000000000..49ce584e36 --- /dev/null +++ b/django/contrib/gis/templates/gis/google/google-multi.js @@ -0,0 +1,8 @@ +{% extends "gis/google/google-base.js" %} +{% block functions %} +{{ load_map_js }} +{{ js_module }}.load = function(){ + {% for dom_id in dom_ids %}{{ js_module }}.{{ dom_id }}_load(); + {% endfor %} +} +{% endblock %} \ No newline at end of file diff --git a/django/contrib/gis/templates/gis/google/google-single.js b/django/contrib/gis/templates/gis/google/google-single.js new file mode 100644 index 0000000000..ab7901e42e --- /dev/null +++ b/django/contrib/gis/templates/gis/google/google-single.js @@ -0,0 +1,2 @@ +{% extends "gis/google/google-base.js" %} +{% block functions %}{% include "gis/google/google-map.js" %}{% endblock %} \ No newline at end of file diff --git a/django/contrib/gis/templates/gis/google/js/google-map.js b/django/contrib/gis/templates/gis/google/js/google-map.js deleted file mode 100644 index 5efdf9045e..0000000000 --- a/django/contrib/gis/templates/gis/google/js/google-map.js +++ /dev/null @@ -1,34 +0,0 @@ -{% autoescape off %}{% block vars %}var map;{% endblock %} -{% block functions %}{% endblock %} -{% block load %}function {{ load_func }}(){ - if (GBrowserIsCompatible()) { - map = new GMap2(document.getElementById("{{ dom_id }}")); - map.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }}); - {% block controls %}map.addControl(new GSmallMapControl()); - map.addControl(new GMapTypeControl());{% endblock %} - {% 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 }}"); - map.addOverlay(kml{{ forloop.counter }});{% endfor %} - - {% for polygon in polygons %}var poly{{ forloop.counter }} = new {{ polygon }}; - map.addOverlay(poly{{ forloop.counter }}); - {% 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 }}; - map.addOverlay(polyline{{ forloop.counter }}); - {% 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 %} - {% block load_extra %}{% endblock %} - }else { - alert("Sorry, the Google Maps API is not compatible with this browser."); - } -} -{% endblock %}{% endautoescape %}