Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #9204 -- Added `GIcon` overlay, allowing customization for icon…

…s 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
  • Loading branch information...
commit 6aa5aacc86a918abd00b2110cc58565193306dd8 1 parent 326c581
Justin Bronn authored March 10, 2009
2  django/contrib/gis/maps/google/__init__.py
@@ -57,5 +57,5 @@
57 57
       version.
58 58
 """
59 59
 from django.contrib.gis.maps.google.gmap import GoogleMap, GoogleMapSet
60  
-from django.contrib.gis.maps.google.overlays import GEvent, GMarker, GPolygon, GPolyline
  60
+from django.contrib.gis.maps.google.overlays import GEvent, GIcon, GMarker, GPolygon, GPolyline
61 61
 from django.contrib.gis.maps.google.zoom import GoogleZoom
60  django/contrib/gis/maps/google/gmap.py
@@ -4,7 +4,7 @@
4 4
 from django.utils.safestring import mark_safe
5 5
 
6 6
 class GoogleMapException(Exception): pass
7  
-from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker
  7
+from django.contrib.gis.maps.google.overlays import GPolygon, GPolyline, GMarker, GIcon
8 8
 
9 9
 # The default Google Maps URL (for the API javascript)
10 10
 # TODO: Internationalize for Japan, UK, etc.
@@ -18,11 +18,12 @@ class GoogleMap(object):
18 18
     vml_css  = mark_safe('v\:* {behavior:url(#default#VML);}') # CSS for IE VML
19 19
     xmlns    = mark_safe('xmlns:v="urn:schemas-microsoft-com:vml"') # XML Namespace (for IE VML).
20 20
 
21  
-    def __init__(self, key=None, api_url=None, version=None, 
  21
+    def __init__(self, key=None, api_url=None, version=None,
22 22
                  center=None, zoom=None, dom_id='map',
23  
-                 kml_urls=[], polygons=[], polylines=[], markers=[],
  23
+                 kml_urls=[], polylines=None, polygons=None, markers=None,
24 24
                  template='gis/google/google-single.js',
25  
-                 js_module='geodjango',extra_context={}):
  25
+                 js_module='geodjango',
  26
+                 extra_context={}):
26 27
 
27 28
         # The Google Maps API Key defined in the settings will be used
28 29
         # if not passed in as a parameter.  The use of an API key is
@@ -34,7 +35,7 @@ def __init__(self, key=None, api_url=None, version=None,
34 35
                 raise GoogleMapException('Google Maps API Key not found (try adding GOOGLE_MAPS_API_KEY to your settings).')
35 36
         else:
36 37
             self.key = key
37  
-        
  38
+
38 39
         # Getting the Google Maps API version, defaults to using the latest ("2.x"),
39 40
         # this is not necessarily the most stable.
40 41
         if not version:
@@ -55,28 +56,24 @@ def __init__(self, key=None, api_url=None, version=None,
55 56
         self.js_module = js_module
56 57
         self.template = template
57 58
         self.kml_urls = kml_urls
58  
-        
  59
+
59 60
         # Does the user want any GMarker, GPolygon, and/or GPolyline overlays?
60  
-        self.polygons, self.polylines, self.markers = [], [], []
61  
-        if markers:
62  
-            for point in markers:
63  
-                if isinstance(point, GMarker): 
64  
-                    self.markers.append(point)
65  
-                else:
66  
-                    self.markers.append(GMarker(point))
67  
-        if polygons:
68  
-            for poly in polygons:
69  
-                if isinstance(poly, GPolygon): 
70  
-                    self.polygons.append(poly)
71  
-                else:
72  
-                    self.polygons.append(GPolygon(poly))
73  
-        if polylines:
74  
-            for pline in polylines:
75  
-                if isinstance(pline, GPolyline):
76  
-                    self.polylines.append(pline)
77  
-                else:
78  
-                    self.polylines.append(GPolyline(pline))
79  
-       
  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
+        # Pulling any icons from the markers.
  75
+        self.icons = [marker.icon for marker in self.markers if marker.icon]
  76
+
80 77
         # If GMarker, GPolygons, and/or GPolylines are used the zoom will be
81 78
         # automatically calculated via the Google Maps API.  If both a zoom
82 79
         # level and a center coordinate are provided with polygons/polylines,
@@ -85,7 +82,7 @@ def __init__(self, key=None, api_url=None, version=None,
85 82
         if self.polygons or self.polylines  or self.markers:
86 83
             if center is None or zoom is None:
87 84
                 self.calc_zoom = True
88  
-    
  85
+
89 86
         # Defaults for the zoom level and center coordinates if the zoom
90 87
         # is not automatically calculated.
91 88
         if zoom is None: zoom = 4
@@ -105,6 +102,7 @@ def render(self):
105 102
                   'zoom' : self.zoom,
106 103
                   'polygons' : self.polygons,
107 104
                   'polylines' : self.polylines,
  105
+                  'icons': self.icons,
108 106
                   'markers' : self.markers,
109 107
                   }
110 108
         params.update(self.extra_context)
@@ -174,7 +172,12 @@ def __init__(self, *args, **kwargs):
174 172
             self.maps = args[0]
175 173
         else:
176 174
             self.maps = args
177  
-        
  175
+
  176
+        # Creating the icons sequence from every map in this set.
  177
+        self.icons = []
  178
+        for map in self.maps:
  179
+            self.icons.extend(map.icons)
  180
+
178 181
         # Generating DOM ids for each of the maps in the set.
179 182
         self.dom_ids = ['map%d' % i for i in xrange(len(self.maps))]
180 183
 
@@ -205,6 +208,7 @@ def render(self):
205 208
         params = {'js_module' : self.js_module,
206 209
                   'dom_ids' : self.dom_ids,
207 210
                   'load_map_js' : self.load_map_js(),
  211
+                  'icons' : self.icons,
208 212
                   }
209 213
         params.update(self.extra_context)
210 214
         return render_to_string(self.template, params)
118  django/contrib/gis/maps/google/overlays.py
@@ -18,28 +18,28 @@ class GEvent(object):
18 18
 
19 19
       def sample_request(request):
20 20
           polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)')
21  
-          event = GEvent('click', 
  21
+          event = GEvent('click',
22 22
             'function() { location.href = "http://www.google.com"}')
23 23
           polyline.add_event(event)
24  
-          return render_to_response('mytemplate.html', 
  24
+          return render_to_response('mytemplate.html',
25 25
           {'google' : GoogleMap(polylines=[polyline])})
26 26
     """
27 27
 
28 28
     def __init__(self, event, action):
29 29
         """
30  
-        Initializes a GEvent object. 
31  
-        
  30
+        Initializes a GEvent object.
  31
+
32 32
         Parameters:
33 33
 
34  
-        event: 
  34
+        event:
35 35
           string for the event, such as 'click'. The event must be a valid
36  
-          event for the object in the Google Maps API. 
  36
+          event for the object in the Google Maps API.
37 37
           There is no validation of the event type within Django.
38 38
 
39 39
         action:
40  
-          string containing a Javascript function, such as 
  40
+          string containing a Javascript function, such as
41 41
           'function() { location.href = "newurl";}'
42  
-          The string must be a valid Javascript function. Again there is no 
  42
+          The string must be a valid Javascript function. Again there is no
43 43
           validation fo the function within Django.
44 44
         """
45 45
         self.event = event
@@ -71,7 +71,7 @@ class GPolygon(GOverlayBase):
71 71
     please see the Google Maps API Reference:
72 72
      http://code.google.com/apis/maps/documentation/reference.html#GPolygon
73 73
     """
74  
-    def __init__(self, poly, 
  74
+    def __init__(self, poly,
75 75
                  stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1,
76 76
                  fill_color='#0000ff', fill_opacity=0.4):
77 77
         """
@@ -98,25 +98,25 @@ def __init__(self, poly,
98 98
         """
99 99
         if isinstance(poly, basestring): poly = fromstr(poly)
100 100
         if isinstance(poly, (tuple, list)): poly = Polygon(poly)
101  
-        if not isinstance(poly, Polygon): 
  101
+        if not isinstance(poly, Polygon):
102 102
             raise TypeError('GPolygon may only initialize on GEOS Polygons.')
103 103
 
104 104
         # Getting the envelope of the input polygon (used for automatically
105 105
         # determining the zoom level).
106 106
         self.envelope = poly.envelope
107 107
 
108  
-        # Translating the coordinates into a JavaScript array of 
  108
+        # Translating the coordinates into a JavaScript array of
109 109
         # Google `GLatLng` objects.
110 110
         self.points = self.latlng_from_coords(poly.shell.coords)
111 111
 
112 112
         # Stroke settings.
113 113
         self.stroke_color, self.stroke_opacity, self.stroke_weight = stroke_color, stroke_opacity, stroke_weight
114  
-      
  114
+
115 115
         # Fill settings.
116 116
         self.fill_color, self.fill_opacity = fill_color, fill_opacity
117  
-       
  117
+
118 118
         super(GPolygon, self).__init__()
119  
- 
  119
+
120 120
     @property
121 121
     def js_params(self):
122 122
         return '%s, "%s", %s, %s, "%s", %s' % (self.points, self.stroke_color, self.stroke_weight, self.stroke_opacity,
@@ -135,10 +135,10 @@ def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
135 135
         may instantiated into one of the above geometries.
136 136
 
137 137
         Keyword Options:
138  
-          
  138
+
139 139
           color:
140 140
             The color to use for the polyline.  Defaults to '#0000ff' (blue).
141  
-  
  141
+
142 142
           weight:
143 143
             The width of the polyline, in pixels.  Defaults to 2.
144 144
 
@@ -160,11 +160,77 @@ def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
160 160
         self.envelope = geom.envelope
161 161
         self.color, self.weight, self.opacity = color, weight, opacity
162 162
         super(GPolyline, self).__init__()
163  
-        
  163
+
164 164
     @property
165 165
     def js_params(self):
166 166
         return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity)
167 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
+
168 234
 class GMarker(GOverlayBase):
169 235
     """
170 236
     A Python wrapper for the Google GMarker object.  For more information
@@ -175,25 +241,25 @@ class GMarker(GOverlayBase):
175 241
 
176 242
       from django.shortcuts import render_to_response
177 243
       from django.contrib.gis.maps.google.overlays import GMarker, GEvent
178  
-     
  244
+
179 245
       def sample_request(request):
180 246
           marker = GMarker('POINT(101 26)')
181  
-          event = GEvent('click', 
  247
+          event = GEvent('click',
182 248
                          'function() { location.href = "http://www.google.com"}')
183 249
           marker.add_event(event)
184  
-          return render_to_response('mytemplate.html', 
  250
+          return render_to_response('mytemplate.html',
185 251
                  {'google' : GoogleMap(markers=[marker])})
186 252
     """
187  
-    def __init__(self, geom, title=None, draggable=False):
  253
+    def __init__(self, geom, title=None, draggable=False, icon=None):
188 254
         """
189 255
         The GMarker object may initialize on GEOS Points or a parameter
190 256
         that may be instantiated into a GEOS point.  Keyword options map to
191 257
         GMarkerOptions -- so far only the title option is supported.
192 258
 
193 259
         Keyword Options:
194  
-         title: 
  260
+         title:
195 261
            Title option for GMarker, will be displayed as a tooltip.
196  
-         
  262
+
197 263
          draggable:
198 264
            Draggable option for GMarker, disabled by default.
199 265
         """
@@ -209,15 +275,17 @@ def __init__(self, geom, title=None, draggable=False):
209 275
         # TODO: Add support for more GMarkerOptions
210 276
         self.title = title
211 277
         self.draggable = draggable
  278
+        self.icon = icon
212 279
         super(GMarker, self).__init__()
213 280
 
214 281
     def latlng_from_coords(self, coords):
215 282
         return 'new GLatLng(%s,%s)' %(coords[1], coords[0])
216  
-    
  283
+
217 284
     def options(self):
218 285
         result = []
219 286
         if self.title: result.append('title: "%s"' % self.title)
220  
-        if self.draggable: result.append('draggable: true') 
  287
+        if self.icon: result.append('icon: %s' % self.icon.varname)
  288
+        if self.draggable: result.append('draggable: true')
221 289
         return '{%s}' % ','.join(result)
222 290
 
223 291
     @property
7  django/contrib/gis/templates/gis/google/google-base.js
... ...
@@ -1,2 +1,7 @@
1  
-{% block vars %}var geodjango = {};{% endblock %}
  1
+{% block vars %}var geodjango = {};{% for icon in icons %} 
  2
+var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON); 
  3
+{% if icon.image %}{{ icon.varname }}.image = "{{ icon.image }}";{% endif %}
  4
+{% if icon.shadow %}{{ icon.varname }}.shadow = "{{ icon.shadow }}";{% endif %} {% if icon.shadowsize %}{{ icon.varname }}.shadowSize = new GSize({{ icon.shadowsize.0 }}, {{ icon.shadowsize.1 }});{% endif %}
  5
+{% 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 %}
  6
+{% if icon.infowindowanchor %}{{ icon.varname }}.infoWindowAnchor = new GPoint({{ icon.infowindowanchor.0 }}, {{ icon.infowindowanchor.1 }});{% endif %}{% endfor %}{% endblock %}
2 7
 {% block functions %}{% endblock %}

0 notes on commit 6aa5aac

Please sign in to comment.
Something went wrong with that request. Please try again.