web/lib/django/contrib/gis/maps/google/overlays.py
changeset 0 0d40e90630ef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/django/contrib/gis/maps/google/overlays.py	Wed Jan 20 00:34:04 2010 +0100
@@ -0,0 +1,301 @@
+from django.utils.safestring import mark_safe
+from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon
+
+class GEvent(object):
+    """
+    A Python wrapper for the Google GEvent object.
+
+    Events can be attached to any object derived from GOverlayBase with the
+    add_event() call.
+
+    For more information please see the Google Maps API Reference:
+     http://code.google.com/apis/maps/documentation/reference.html#GEvent
+
+    Example:
+
+      from django.shortcuts import render_to_response
+      from django.contrib.gis.maps.google import GoogleMap, GEvent, GPolyline
+
+      def sample_request(request):
+          polyline = GPolyline('LINESTRING(101 26, 112 26, 102 31)')
+          event = GEvent('click',
+            'function() { location.href = "http://www.google.com"}')
+          polyline.add_event(event)
+          return render_to_response('mytemplate.html',
+          {'google' : GoogleMap(polylines=[polyline])})
+    """
+
+    def __init__(self, event, action):
+        """
+        Initializes a GEvent object.
+
+        Parameters:
+
+        event:
+          string for the event, such as 'click'. The event must be a valid
+          event for the object in the Google Maps API.
+          There is no validation of the event type within Django.
+
+        action:
+          string containing a Javascript function, such as
+          'function() { location.href = "newurl";}'
+          The string must be a valid Javascript function. Again there is no
+          validation fo the function within Django.
+        """
+        self.event = event
+        self.action = action
+
+    def __unicode__(self):
+        "Returns the parameter part of a GEvent."
+        return mark_safe('"%s", %s' %(self.event, self.action))
+
+class GOverlayBase(object):
+    def __init__(self):
+        self.events = []
+
+    def latlng_from_coords(self, coords):
+        "Generates a JavaScript array of GLatLng objects for the given coordinates."
+        return '[%s]' % ','.join(['new GLatLng(%s,%s)' % (y, x) for x, y in coords])
+
+    def add_event(self, event):
+        "Attaches a GEvent to the overlay object."
+        self.events.append(event)
+
+    def __unicode__(self):
+        "The string representation is the JavaScript API call."
+        return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
+
+class GPolygon(GOverlayBase):
+    """
+    A Python wrapper for the Google GPolygon object.  For more information
+    please see the Google Maps API Reference:
+     http://code.google.com/apis/maps/documentation/reference.html#GPolygon
+    """
+    def __init__(self, poly,
+                 stroke_color='#0000ff', stroke_weight=2, stroke_opacity=1,
+                 fill_color='#0000ff', fill_opacity=0.4):
+        """
+        The GPolygon object initializes on a GEOS Polygon or a parameter that
+        may be instantiated into GEOS Polygon.  Please note that this will not
+        depict a Polygon's internal rings.
+
+        Keyword Options:
+
+          stroke_color:
+            The color of the polygon outline. Defaults to '#0000ff' (blue).
+
+          stroke_weight:
+            The width of the polygon outline, in pixels.  Defaults to 2.
+
+          stroke_opacity:
+            The opacity of the polygon outline, between 0 and 1.  Defaults to 1.
+
+          fill_color:
+            The color of the polygon fill.  Defaults to '#0000ff' (blue).
+
+          fill_opacity:
+            The opacity of the polygon fill.  Defaults to 0.4.
+        """
+        if isinstance(poly, basestring): poly = fromstr(poly)
+        if isinstance(poly, (tuple, list)): poly = Polygon(poly)
+        if not isinstance(poly, Polygon):
+            raise TypeError('GPolygon may only initialize on GEOS Polygons.')
+
+        # Getting the envelope of the input polygon (used for automatically
+        # determining the zoom level).
+        self.envelope = poly.envelope
+
+        # Translating the coordinates into a JavaScript array of
+        # Google `GLatLng` objects.
+        self.points = self.latlng_from_coords(poly.shell.coords)
+
+        # Stroke settings.
+        self.stroke_color, self.stroke_opacity, self.stroke_weight = stroke_color, stroke_opacity, stroke_weight
+
+        # Fill settings.
+        self.fill_color, self.fill_opacity = fill_color, fill_opacity
+
+        super(GPolygon, self).__init__()
+
+    @property
+    def js_params(self):
+        return '%s, "%s", %s, %s, "%s", %s' % (self.points, self.stroke_color, self.stroke_weight, self.stroke_opacity,
+                                               self.fill_color, self.fill_opacity)
+
+class GPolyline(GOverlayBase):
+    """
+    A Python wrapper for the Google GPolyline object.  For more information
+    please see the Google Maps API Reference:
+     http://code.google.com/apis/maps/documentation/reference.html#GPolyline
+    """
+    def __init__(self, geom, color='#0000ff', weight=2, opacity=1):
+        """
+        The GPolyline object may be initialized on GEOS LineStirng, LinearRing,
+        and Polygon objects (internal rings not supported) or a parameter that
+        may instantiated into one of the above geometries.
+
+        Keyword Options:
+
+          color:
+            The color to use for the polyline.  Defaults to '#0000ff' (blue).
+
+          weight:
+            The width of the polyline, in pixels.  Defaults to 2.
+
+          opacity:
+            The opacity of the polyline, between 0 and 1.  Defaults to 1.
+        """
+        # If a GEOS geometry isn't passed in, try to contsruct one.
+        if isinstance(geom, basestring): geom = fromstr(geom)
+        if isinstance(geom, (tuple, list)): geom = Polygon(geom)
+        # Generating the lat/lng coordinate pairs.
+        if isinstance(geom, (LineString, LinearRing)):
+            self.latlngs = self.latlng_from_coords(geom.coords)
+        elif isinstance(geom, Polygon):
+            self.latlngs = self.latlng_from_coords(geom.shell.coords)
+        else:
+            raise TypeError('GPolyline may only initialize on GEOS LineString, LinearRing, and/or Polygon geometries.')
+
+        # Getting the envelope for automatic zoom determination.
+        self.envelope = geom.envelope
+        self.color, self.weight, self.opacity = color, weight, opacity
+        super(GPolyline, self).__init__()
+
+    @property
+    def js_params(self):
+        return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity)
+
+
+class GIcon(object):
+    """
+    Creates a GIcon object to pass into a Gmarker object.
+
+    The keyword arguments map to instance attributes of the same name. These,
+    in turn, correspond to a subset of the attributes of the official GIcon
+    javascript object:
+
+    http://code.google.com/apis/maps/documentation/reference.html#GIcon
+
+    Because a Google map often uses several different icons, a name field has
+    been added to the required arguments.
+
+    Required Arguments:
+        varname:
+            A string which will become the basis for the js variable name of
+            the marker, for this reason, your code should assign a unique
+            name for each GIcon you instantiate, otherwise there will be
+            name space collisions in your javascript.
+
+    Keyword Options:
+        image:
+            The url of the image to be used as the icon on the map defaults
+            to 'G_DEFAULT_ICON'
+
+        iconsize:
+            a tuple representing the pixel size of the foreground (not the
+            shadow) image of the icon, in the format: (width, height) ex.:
+
+            GIcon('fast_food',
+                  image="/media/icon/star.png",
+                  iconsize=(15,10))
+
+            Would indicate your custom icon was 15px wide and 10px height.
+
+        shadow:
+            the url of the image of the icon's shadow
+
+        shadowsize:
+            a tuple representing the pixel size of the shadow image, format is
+            the same as ``iconsize``
+
+        iconanchor:
+            a tuple representing the pixel coordinate relative to the top left
+            corner of the icon image at which this icon is anchored to the map.
+            In (x, y) format.  x increases to the right in the Google Maps
+            coordinate system and y increases downwards in the Google Maps
+            coordinate system.)
+
+        infowindowanchor:
+            The pixel coordinate relative to the top left corner of the icon
+            image at which the info window is anchored to this icon.
+
+    """
+    def __init__(self, varname, image=None, iconsize=None,
+                 shadow=None, shadowsize=None, iconanchor=None,
+                 infowindowanchor=None):
+        self.varname = varname
+        self.image = image
+        self.iconsize = iconsize
+        self.shadow = shadow
+        self.shadowsize = shadowsize
+        self.iconanchor = iconanchor
+        self.infowindowanchor = infowindowanchor
+
+    def __cmp__(self, other):
+        return cmp(self.varname, other.varname)
+    
+    def __hash__(self):
+        # XOR with hash of GIcon type so that hash('varname') won't 
+        # equal hash(GIcon('varname')).
+        return hash(self.__class__) ^ hash(self.varname)
+
+class GMarker(GOverlayBase):
+    """
+    A Python wrapper for the Google GMarker object.  For more information
+    please see the Google Maps API Reference:
+     http://code.google.com/apis/maps/documentation/reference.html#GMarker
+
+    Example:
+
+      from django.shortcuts import render_to_response
+      from django.contrib.gis.maps.google.overlays import GMarker, GEvent
+
+      def sample_request(request):
+          marker = GMarker('POINT(101 26)')
+          event = GEvent('click',
+                         'function() { location.href = "http://www.google.com"}')
+          marker.add_event(event)
+          return render_to_response('mytemplate.html',
+                 {'google' : GoogleMap(markers=[marker])})
+    """
+    def __init__(self, geom, title=None, draggable=False, icon=None):
+        """
+        The GMarker object may initialize on GEOS Points or a parameter
+        that may be instantiated into a GEOS point.  Keyword options map to
+        GMarkerOptions -- so far only the title option is supported.
+
+        Keyword Options:
+         title:
+           Title option for GMarker, will be displayed as a tooltip.
+
+         draggable:
+           Draggable option for GMarker, disabled by default.
+        """
+        # If a GEOS geometry isn't passed in, try to construct one.
+        if isinstance(geom, basestring): geom = fromstr(geom)
+        if isinstance(geom, (tuple, list)): geom = Point(geom)
+        if isinstance(geom, Point):
+            self.latlng = self.latlng_from_coords(geom.coords)
+        else:
+            raise TypeError('GMarker may only initialize on GEOS Point geometry.')
+        # Getting the envelope for automatic zoom determination.
+        self.envelope = geom.envelope
+        # TODO: Add support for more GMarkerOptions
+        self.title = title
+        self.draggable = draggable
+        self.icon = icon
+        super(GMarker, self).__init__()
+
+    def latlng_from_coords(self, coords):
+        return 'new GLatLng(%s,%s)' %(coords[1], coords[0])
+
+    def options(self):
+        result = []
+        if self.title: result.append('title: "%s"' % self.title)
+        if self.icon: result.append('icon: %s' % self.icon.varname)
+        if self.draggable: result.append('draggable: true')
+        return '{%s}' % ','.join(result)
+
+    @property
+    def js_params(self):
+        return '%s, %s' % (self.latlng, self.options())