from __future__ import unicode_literals import logging from django.conf import settings from django.contrib.gis import gdal from django.contrib.gis.geos import GEOSGeometry, GEOSException from django.forms.widgets import Widget from django.template import loader from django.utils import six from django.utils import translation logger = logging.getLogger('django.contrib.gis') class BaseGeometryWidget(Widget): """ The base class for rich geometry widgets. Renders a map using the WKT of the geometry. """ geom_type = 'GEOMETRY' map_srid = 4326 map_width = 600 map_height = 400 display_wkt = False supports_3d = False template_name = '' # set on subclasses def __init__(self, attrs=None): self.attrs = {} for key in ('geom_type', 'map_srid', 'map_width', 'map_height', 'display_wkt'): self.attrs[key] = getattr(self, key) if attrs: self.attrs.update(attrs) def render(self, name, value, attrs=None): # If a string reaches here (via a validation error on another # field) then just reconstruct the Geometry. if isinstance(value, six.string_types): try: value = GEOSGeometry(value) except (GEOSException, ValueError) as err: logger.error( "Error creating geometry from value '%s' (%s)" % ( value, err) ) value = None wkt = '' if value: # Check that srid of value and map match if value.srid != self.map_srid: try: ogr = value.ogr ogr.transform(self.map_srid) wkt = ogr.wkt except gdal.OGRException as err: logger.error( "Error transforming geometry from srid '%s' to srid '%s' (%s)" % ( value.srid, self.map_srid, err) ) else: wkt = value.wkt context = self.build_attrs(attrs, name=name, module='geodjango_%s' % name.replace('-','_'), # JS-safe wkt=wkt, geom_type=gdal.OGRGeomType(self.attrs['geom_type']), STATIC_URL=settings.STATIC_URL, LANGUAGE_BIDI=translation.get_language_bidi(), ) return loader.render_to_string(self.template_name, context) class OpenLayersWidget(BaseGeometryWidget): template_name = 'gis/openlayers.html' class Media: js = ( 'http://openlayers.org/api/2.11/OpenLayers.js', 'gis/js/OLMapWidget.js', ) class OSMWidget(BaseGeometryWidget): """ An OpenLayers/OpenStreetMap-based widget. """ template_name = 'gis/openlayers-osm.html' default_lon = 5 default_lat = 47 class Media: js = ( 'http://openlayers.org/api/2.11/OpenLayers.js', 'http://www.openstreetmap.org/openlayers/OpenStreetMap.js', 'gis/js/OLMapWidget.js', ) @property def map_srid(self): # Use the official spherical mercator projection SRID on versions # of GDAL that support it; otherwise, fallback to 900913. if gdal.HAS_GDAL and gdal.GDAL_VERSION >= (1, 7): return 3857 else: return 900913 def render(self, name, value, attrs=None): return super(self, OSMWidget).render(name, value, {'default_lon': self.default_lon, 'default_lat': self.default_lat})