You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

widgets.py 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import logging
  2. from django.contrib.gis.gdal import GDALException
  3. from django.contrib.gis.geos import GEOSException, GEOSGeometry
  4. from django.forms.widgets import Textarea
  5. from django.utils import translation
  6. # Creating a template context that contains Django settings
  7. # values needed by admin map templates.
  8. geo_context = {'LANGUAGE_BIDI': translation.get_language_bidi()}
  9. logger = logging.getLogger('django.contrib.gis')
  10. class OpenLayersWidget(Textarea):
  11. """
  12. Render an OpenLayers map using the WKT of the geometry.
  13. """
  14. def get_context(self, name, value, attrs):
  15. # Update the template parameters with any attributes passed in.
  16. if attrs:
  17. self.params.update(attrs)
  18. self.params['editable'] = self.params['modifiable']
  19. else:
  20. self.params['editable'] = True
  21. # Defaulting the WKT value to a blank string -- this
  22. # will be tested in the JavaScript and the appropriate
  23. # interface will be constructed.
  24. self.params['wkt'] = ''
  25. # If a string reaches here (via a validation error on another
  26. # field) then just reconstruct the Geometry.
  27. if value and isinstance(value, str):
  28. try:
  29. value = GEOSGeometry(value)
  30. except (GEOSException, ValueError) as err:
  31. logger.error("Error creating geometry from value '%s' (%s)", value, err)
  32. value = None
  33. if (value and value.geom_type.upper() != self.geom_type and
  34. self.geom_type != 'GEOMETRY'):
  35. value = None
  36. # Constructing the dictionary of the map options.
  37. self.params['map_options'] = self.map_options()
  38. # Constructing the JavaScript module name using the name of
  39. # the GeometryField (passed in via the `attrs` keyword).
  40. # Use the 'name' attr for the field name (rather than 'field')
  41. self.params['name'] = name
  42. # note: we must switch out dashes for underscores since js
  43. # functions are created using the module variable
  44. js_safe_name = self.params['name'].replace('-', '_')
  45. self.params['module'] = 'geodjango_%s' % js_safe_name
  46. if value:
  47. # Transforming the geometry to the projection used on the
  48. # OpenLayers map.
  49. srid = self.params['srid']
  50. if value.srid != srid:
  51. try:
  52. ogr = value.ogr
  53. ogr.transform(srid)
  54. wkt = ogr.wkt
  55. except GDALException as err:
  56. logger.error(
  57. "Error transforming geometry from srid '%s' to srid '%s' (%s)",
  58. value.srid, srid, err
  59. )
  60. wkt = ''
  61. else:
  62. wkt = value.wkt
  63. # Setting the parameter WKT with that of the transformed
  64. # geometry.
  65. self.params['wkt'] = wkt
  66. self.params.update(geo_context)
  67. return self.params
  68. def map_options(self):
  69. """Build the map options hash for the OpenLayers template."""
  70. # JavaScript construction utilities for the Bounds and Projection.
  71. def ol_bounds(extent):
  72. return 'new OpenLayers.Bounds(%s)' % extent
  73. def ol_projection(srid):
  74. return 'new OpenLayers.Projection("EPSG:%s")' % srid
  75. # An array of the parameter name, the name of their OpenLayers
  76. # counterpart, and the type of variable they are.
  77. map_types = [('srid', 'projection', 'srid'),
  78. ('display_srid', 'displayProjection', 'srid'),
  79. ('units', 'units', str),
  80. ('max_resolution', 'maxResolution', float),
  81. ('max_extent', 'maxExtent', 'bounds'),
  82. ('num_zoom', 'numZoomLevels', int),
  83. ('max_zoom', 'maxZoomLevels', int),
  84. ('min_zoom', 'minZoomLevel', int),
  85. ]
  86. # Building the map options hash.
  87. map_options = {}
  88. for param_name, js_name, option_type in map_types:
  89. if self.params.get(param_name, False):
  90. if option_type == 'srid':
  91. value = ol_projection(self.params[param_name])
  92. elif option_type == 'bounds':
  93. value = ol_bounds(self.params[param_name])
  94. elif option_type in (float, int):
  95. value = self.params[param_name]
  96. elif option_type in (str,):
  97. value = '"%s"' % self.params[param_name]
  98. else:
  99. raise TypeError
  100. map_options[js_name] = value
  101. return map_options