mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
gis: Added the geographic-enabled forms and admin modules.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7980 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
149e731c3c
commit
2995f4e509
BIN
django/contrib/admin/media/img/gis/move_vertex_off.png
Normal file
BIN
django/contrib/admin/media/img/gis/move_vertex_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 711 B |
BIN
django/contrib/admin/media/img/gis/move_vertex_on.png
Normal file
BIN
django/contrib/admin/media/img/gis/move_vertex_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 506 B |
9
django/contrib/gis/admin/__init__.py
Normal file
9
django/contrib/gis/admin/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from django.contrib.gis.admin.options import GeoModelAdmin
|
||||||
|
from django.contrib.gis.admin.sites import GeoAdminSite, site
|
||||||
|
from django.contrib.gis.admin.widgets import OpenLayersWidget
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.contrib.gis.admin.options import OSMGeoAdmin
|
||||||
|
HAS_OSM = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_OSM = False
|
128
django/contrib/gis/admin/options.py
Normal file
128
django/contrib/gis/admin/options.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.admin import ModelAdmin
|
||||||
|
from django.contrib.gis.admin.widgets import OpenLayersWidget
|
||||||
|
from django.contrib.gis.gdal import OGRGeomType
|
||||||
|
from django.contrib.gis.db import models
|
||||||
|
|
||||||
|
class GeoModelAdmin(ModelAdmin):
|
||||||
|
"""
|
||||||
|
The administration options class for Geographic models. Map settings
|
||||||
|
may be overloaded from their defaults to create custom maps.
|
||||||
|
"""
|
||||||
|
# The default map settings that may be overloaded -- still subject
|
||||||
|
# to API changes.
|
||||||
|
default_lon = 0
|
||||||
|
default_lat = 0
|
||||||
|
default_zoom = 4
|
||||||
|
display_wkt = False
|
||||||
|
display_srid = False
|
||||||
|
extra_js = []
|
||||||
|
num_zoom = 18
|
||||||
|
max_zoom = False
|
||||||
|
min_zoom = False
|
||||||
|
units = False
|
||||||
|
max_resolution = False
|
||||||
|
max_extent = False
|
||||||
|
modifiable = True
|
||||||
|
mouse_position = True
|
||||||
|
scale_text = True
|
||||||
|
layerswitcher = True
|
||||||
|
scrollable = True
|
||||||
|
admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
|
||||||
|
map_width = 600
|
||||||
|
map_height = 400
|
||||||
|
map_srid = 4326
|
||||||
|
map_template = 'gis/admin/openlayers.html'
|
||||||
|
openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
|
||||||
|
wms_url = 'http://labs.metacarta.com/wms/vmap0'
|
||||||
|
wms_layer = 'basic'
|
||||||
|
wms_name = 'OpenLayers WMS'
|
||||||
|
debug = False
|
||||||
|
widget = OpenLayersWidget
|
||||||
|
|
||||||
|
def _media(self):
|
||||||
|
"Injects OpenLayers JavaScript into the admin."
|
||||||
|
media = super(GeoModelAdmin, self)._media()
|
||||||
|
media.add_js([self.openlayers_url])
|
||||||
|
media.add_js(self.extra_js)
|
||||||
|
return media
|
||||||
|
media = property(_media)
|
||||||
|
|
||||||
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
|
"""
|
||||||
|
Overloaded from ModelAdmin so that an OpenLayersWidget is used
|
||||||
|
for viewing/editing GeometryFields.
|
||||||
|
"""
|
||||||
|
if isinstance(db_field, models.GeometryField):
|
||||||
|
# Setting the widget with the newly defined widget.
|
||||||
|
kwargs['widget'] = self.get_map_widget(db_field)
|
||||||
|
return db_field.formfield(**kwargs)
|
||||||
|
else:
|
||||||
|
return super(GeoModelAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
def get_map_widget(self, db_field):
|
||||||
|
"""
|
||||||
|
Returns a subclass of the OpenLayersWidget (or whatever was specified
|
||||||
|
in the `widget` attribute) using the settings from the attributes set
|
||||||
|
in this class.
|
||||||
|
"""
|
||||||
|
is_collection = db_field._geom in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION')
|
||||||
|
if is_collection:
|
||||||
|
if db_field._geom == 'GEOMETRYCOLLECTION': collection_type = 'Any'
|
||||||
|
else: collection_type = OGRGeomType(db_field._geom.replace('MULTI', ''))
|
||||||
|
else:
|
||||||
|
collection_type = 'None'
|
||||||
|
|
||||||
|
class OLMap(self.widget):
|
||||||
|
template = self.map_template
|
||||||
|
geom_type = db_field._geom
|
||||||
|
params = {'admin_media_prefix' : self.admin_media_prefix,
|
||||||
|
'default_lon' : self.default_lon,
|
||||||
|
'default_lat' : self.default_lat,
|
||||||
|
'default_zoom' : self.default_zoom,
|
||||||
|
'display_wkt' : self.debug or self.display_wkt,
|
||||||
|
'geom_type' : OGRGeomType(db_field._geom),
|
||||||
|
'field_name' : db_field.name,
|
||||||
|
'is_collection' : is_collection,
|
||||||
|
'scrollable' : self.scrollable,
|
||||||
|
'layerswitcher' : self.layerswitcher,
|
||||||
|
'collection_type' : collection_type,
|
||||||
|
'is_linestring' : db_field._geom in ('LINESTRING', 'MULTILINESTRING'),
|
||||||
|
'is_polygon' : db_field._geom in ('POLYGON', 'MULTIPOLYGON'),
|
||||||
|
'is_point' : db_field._geom in ('POINT', 'MULTIPOINT'),
|
||||||
|
'num_zoom' : self.num_zoom,
|
||||||
|
'max_zoom' : self.max_zoom,
|
||||||
|
'min_zoom' : self.min_zoom,
|
||||||
|
'units' : self.units, #likely shoud get from object
|
||||||
|
'max_resolution' : self.max_resolution,
|
||||||
|
'max_extent' : self.max_extent,
|
||||||
|
'modifiable' : self.modifiable,
|
||||||
|
'mouse_position' : self.mouse_position,
|
||||||
|
'scale_text' : self.scale_text,
|
||||||
|
'map_width' : self.map_width,
|
||||||
|
'map_height' : self.map_height,
|
||||||
|
'srid' : self.map_srid,
|
||||||
|
'display_srid' : self.display_srid,
|
||||||
|
'wms_url' : self.wms_url,
|
||||||
|
'wms_layer' : self.wms_layer,
|
||||||
|
'wms_name' : self.wms_name,
|
||||||
|
'debug' : self.debug,
|
||||||
|
}
|
||||||
|
return OLMap
|
||||||
|
|
||||||
|
# Using the Beta OSM in the admin requires the following:
|
||||||
|
# (1) The Google Maps Mercator projection needs to be added
|
||||||
|
# to your `spatial_ref_sys` table. You'll need at least GDAL 1.5:
|
||||||
|
# >>> from django.contrib.gis.gdal import SpatialReference
|
||||||
|
# >>> from django.contrib.gis.utils import add_postgis_srs
|
||||||
|
# >>> add_postgis_srs(SpatialReference(900913)) # Adding the Google Projection
|
||||||
|
from django.contrib.gis import gdal
|
||||||
|
if gdal.HAS_GDAL:
|
||||||
|
class OSMGeoAdmin(GeoModelAdmin):
|
||||||
|
map_template = 'gis/admin/osm.html'
|
||||||
|
extra_js = ['http://openstreetmap.org/openlayers/OpenStreetMap.js']
|
||||||
|
num_zoom = 20
|
||||||
|
map_srid = 900913
|
||||||
|
max_extent = '-20037508,-20037508,20037508,20037508'
|
||||||
|
max_resolution = 156543.0339
|
||||||
|
units = 'm'
|
37
django/contrib/gis/admin/sites.py
Normal file
37
django/contrib/gis/admin/sites.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from django.contrib.admin import sites
|
||||||
|
from django.contrib.gis.admin.options import GeoModelAdmin
|
||||||
|
from django.db.models.loading import get_apps
|
||||||
|
|
||||||
|
class GeoAdminSite(sites.AdminSite):
|
||||||
|
"""
|
||||||
|
The GeoAdminSite is overloaded from the AdminSite to provide facilities
|
||||||
|
for editing geographic fields (using the GeoModelAdmin for the options
|
||||||
|
class instead of ModelAdmin).
|
||||||
|
"""
|
||||||
|
def register(self, model_or_iterable, admin_class=None, **options):
|
||||||
|
"Overloaded register method that uses GeoModelAdmin."
|
||||||
|
admin_class = admin_class or GeoModelAdmin
|
||||||
|
try:
|
||||||
|
return super(GeoAdminSite, self).register(model_or_iterable, admin_class, **options)
|
||||||
|
except sites.AlreadyRegistered:
|
||||||
|
# Unlike the default behavior in newforms-admin we won't
|
||||||
|
# raise this exception.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# `site` is an instance of GeoAdminSite
|
||||||
|
site = GeoAdminSite()
|
||||||
|
|
||||||
|
# Re-registering models that appear normally in AdminSite with the
|
||||||
|
# GeoAdminSite (if the user has these installed).
|
||||||
|
APPS = get_apps()
|
||||||
|
|
||||||
|
# Registering the `auth` Group & User models.
|
||||||
|
from django.contrib.auth import models, admin
|
||||||
|
if models in APPS:
|
||||||
|
site.register(models.Group, admin.GroupAdmin)
|
||||||
|
site.register(models.User, admin.UserAdmin)
|
||||||
|
|
||||||
|
# Registering the `sites` Site model.
|
||||||
|
from django.contrib.sites import models, admin
|
||||||
|
if models in APPS:
|
||||||
|
site.register(models.Site, admin.SiteAdmin)
|
92
django/contrib/gis/admin/widgets.py
Normal file
92
django/contrib/gis/admin/widgets.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from django.contrib.gis.gdal import OGRException
|
||||||
|
from django.contrib.gis.geos import GEOSGeometry, GEOSException
|
||||||
|
from django.forms.widgets import Textarea
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
class OpenLayersWidget(Textarea):
|
||||||
|
"""
|
||||||
|
Renders an OpenLayers map using the WKT of the geometry.
|
||||||
|
"""
|
||||||
|
def render(self, name, value, attrs=None):
|
||||||
|
# Update the template parameters with any attributes passed in.
|
||||||
|
if attrs: self.params.update(attrs)
|
||||||
|
|
||||||
|
# Defaulting the WKT value to a blank string -- this
|
||||||
|
# will be tested in the JavaScript and the appropriate
|
||||||
|
# interfaace will be constructed.
|
||||||
|
self.params['wkt'] = ''
|
||||||
|
|
||||||
|
# If a string reaches here (via a validation error on another
|
||||||
|
# field) then just reconstruct the Geometry.
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
try:
|
||||||
|
value = GEOSGeometry(value)
|
||||||
|
except (GEOSException, ValueError):
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if value and value.geom_type.upper() != self.geom_type:
|
||||||
|
value = None
|
||||||
|
|
||||||
|
# Constructing the dictionary of the map options.
|
||||||
|
self.params['map_options'] = self.map_options()
|
||||||
|
|
||||||
|
# Constructing the JavaScript module name using the ID of
|
||||||
|
# the GeometryField (passed in via the `attrs` keyword).
|
||||||
|
self.params['module'] = 'geodjango_%s' % self.params['field_name']
|
||||||
|
|
||||||
|
if value:
|
||||||
|
# Transforming the geometry to the projection used on the
|
||||||
|
# OpenLayers map.
|
||||||
|
srid = self.params['srid']
|
||||||
|
if value.srid != srid:
|
||||||
|
try:
|
||||||
|
value.transform(srid)
|
||||||
|
wkt = value.wkt
|
||||||
|
except OGRException:
|
||||||
|
wkt = ''
|
||||||
|
else:
|
||||||
|
wkt = value.wkt
|
||||||
|
|
||||||
|
# Setting the parameter WKT with that of the transformed
|
||||||
|
# geometry.
|
||||||
|
self.params['wkt'] = wkt
|
||||||
|
|
||||||
|
return render_to_string(self.template, self.params)
|
||||||
|
|
||||||
|
def map_options(self):
|
||||||
|
"Builds the map options hash for the OpenLayers template."
|
||||||
|
|
||||||
|
# JavaScript construction utilities for the Bounds and Projection.
|
||||||
|
def ol_bounds(extent):
|
||||||
|
return 'new OpenLayers.Bounds(%s)' % str(extent)
|
||||||
|
def ol_projection(srid):
|
||||||
|
return 'new OpenLayers.Projection("EPSG:%s")' % srid
|
||||||
|
|
||||||
|
# An array of the parameter name, the name of their OpenLayers
|
||||||
|
# counterpart, and the type of variable they are.
|
||||||
|
map_types = [('srid', 'projection', 'srid'),
|
||||||
|
('display_srid', 'displayProjection', 'srid'),
|
||||||
|
('units', 'units', str),
|
||||||
|
('max_resolution', 'maxResolution', float),
|
||||||
|
('max_extent', 'maxExtent', 'bounds'),
|
||||||
|
('num_zoom', 'numZoomLevels', int),
|
||||||
|
('max_zoom', 'maxZoomLevels', int),
|
||||||
|
('min_zoom', 'minZoomLevel', int),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Building the map options hash.
|
||||||
|
map_options = {}
|
||||||
|
for param_name, js_name, option_type in map_types:
|
||||||
|
if self.params.get(param_name, False):
|
||||||
|
if option_type == 'srid':
|
||||||
|
value = ol_projection(self.params[param_name])
|
||||||
|
elif option_type == 'bounds':
|
||||||
|
value = ol_bounds(self.params[param_name])
|
||||||
|
elif option_type in (float, int):
|
||||||
|
value = self.params[param_name]
|
||||||
|
elif option_type in (str,):
|
||||||
|
value = '"%s"' % self.params[param_name]
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
map_options[js_name] = value
|
||||||
|
return map_options
|
@ -1,3 +1,4 @@
|
|||||||
|
from django.contrib.gis import forms
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
# Getting the SpatialBackend container and the geographic quoting method.
|
# Getting the SpatialBackend container and the geographic quoting method.
|
||||||
from django.contrib.gis.db.backend import SpatialBackend, gqn
|
from django.contrib.gis.db.backend import SpatialBackend, gqn
|
||||||
@ -111,7 +112,7 @@ class GeometryField(SpatialBackend.Field):
|
|||||||
except SpatialBackend.GeometryException:
|
except SpatialBackend.GeometryException:
|
||||||
raise ValueError('Could not create geometry from lookup value: %s' % str(value))
|
raise ValueError('Could not create geometry from lookup value: %s' % str(value))
|
||||||
else:
|
else:
|
||||||
raise TypeError('Cannot use parameter of `%s` type as a geometry lookup parameter.' % type(value))
|
raise TypeError('Cannot use parameter of `%s` type as lookup parameter.' % type(value))
|
||||||
|
|
||||||
# Assigning the SRID value.
|
# Assigning the SRID value.
|
||||||
geom.srid = self.get_srid(geom)
|
geom.srid = self.get_srid(geom)
|
||||||
@ -137,6 +138,14 @@ class GeometryField(SpatialBackend.Field):
|
|||||||
# Setup for lazy-instantiated Geometry object.
|
# Setup for lazy-instantiated Geometry object.
|
||||||
setattr(cls, self.attname, GeometryProxy(SpatialBackend.Geometry, self))
|
setattr(cls, self.attname, GeometryProxy(SpatialBackend.Geometry, self))
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {'form_class' : forms.GeometryField,
|
||||||
|
'geom_type' : self._geom,
|
||||||
|
'null' : self.null,
|
||||||
|
}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(GeometryField, self).formfield(**defaults)
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
"""
|
"""
|
||||||
Returns the spatial WHERE clause and associated parameters for the
|
Returns the spatial WHERE clause and associated parameters for the
|
||||||
|
1
django/contrib/gis/forms/__init__.py
Normal file
1
django/contrib/gis/forms/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from django.contrib.gis.forms.fields import GeometryField
|
37
django/contrib/gis/forms/fields.py
Normal file
37
django/contrib/gis/forms/fields.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.contrib.gis.geos import GEOSGeometry, GEOSException
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
class GeometryField(forms.Field):
|
||||||
|
# By default a Textarea widget is used.
|
||||||
|
widget = forms.Textarea
|
||||||
|
|
||||||
|
default_error_messages = {
|
||||||
|
'no_geom' : _(u'No geometry value provided.'),
|
||||||
|
'invalid_geom' : _(u'Invalid Geometry value.'),
|
||||||
|
'invalid_geom_type' : _(u'Invalid Geometry type.'),
|
||||||
|
}
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.null = kwargs.pop('null')
|
||||||
|
self.geom_type = kwargs.pop('geom_type')
|
||||||
|
super(GeometryField, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Validates that the input value can be converted to a Geometry
|
||||||
|
object (which is returned). A ValidationError is raised if
|
||||||
|
the value cannot be instantiated as a Geometry.
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
if self.null:
|
||||||
|
# The geometry column allows NULL, return None.
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
raise forms.ValidationError(self.error_messages['no_geom'])
|
||||||
|
try:
|
||||||
|
geom = GEOSGeometry(value)
|
||||||
|
if geom.geom_type.upper() != self.geom_type:
|
||||||
|
raise forms.ValidationError(self.error_messages['invalid_geom_type'])
|
||||||
|
return geom
|
||||||
|
except GEOSException:
|
||||||
|
raise forms.ValidationError(self.error_messages['invalid_geom'])
|
37
django/contrib/gis/templates/gis/admin/openlayers.html
Normal file
37
django/contrib/gis/templates/gis/admin/openlayers.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{% block extrastyle %}
|
||||||
|
<style type="text/css">
|
||||||
|
#{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; }
|
||||||
|
#{{ id }}_map .aligned label { float:inherit; }
|
||||||
|
#{{ id }}_admin_map { position: relative; vertical-align: top; float: left; }
|
||||||
|
{% if not display_wkt %}#{{ id }} { display: none; }{% endif %}
|
||||||
|
.olControlEditingToolbar .olControlModifyFeatureItemActive {
|
||||||
|
background-image: url("{{ admin_media_prefix }}img/gis/move_vertex_on.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.olControlEditingToolbar .olControlModifyFeatureItemInactive {
|
||||||
|
background-image: url("{{ admin_media_prefix }}img/gis/move_vertex_off.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!--[if IE]>
|
||||||
|
<style type="text/css">
|
||||||
|
/* This fixes the the mouse offset issues in IE. */
|
||||||
|
#{{ id }}_admin_map { position: static; vertical-align: top; }
|
||||||
|
/* `font-size: 0` fixes the 1px border between tiles, but borks LayerSwitcher.
|
||||||
|
Thus, this is disabled until a better fix is found.
|
||||||
|
#{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; font-size: 0; } */
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
{% endblock %}
|
||||||
|
<span id="{{ id }}_admin_map">
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
{% block openlayers %}{% include "gis/admin/openlayers.js" %}{% endblock %}
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
<div id="{{ id }}_map"></div>
|
||||||
|
<a href="javascript:{{ module }}.clearFeatures()">Delete all Features</a>
|
||||||
|
{% if display_wkt %}<p> WKT debugging window:</p>{% endif %}
|
||||||
|
<textarea id="{{ id }}" class="vWKTField required" cols="150" rows="10" name="{{ field_name }}">{{ wkt }}</textarea>
|
||||||
|
<script type="text/javascript">{% block init_function %}{{ module }}.init();{% endblock %}</script>
|
||||||
|
</span>
|
157
django/contrib/gis/templates/gis/admin/openlayers.js
Normal file
157
django/contrib/gis/templates/gis/admin/openlayers.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
{# Author: Justin Bronn, Travis Pinney & Dane Springmeyer #}
|
||||||
|
{% block vars %}var {{ module }} = {};
|
||||||
|
{{ module }}.map = null; {{ module }}.controls = null; {{ module }}.panel = null; {{ module }}.re = new RegExp("^SRID=\d+;(.+)", "i"); {{ module }}.layers = {};
|
||||||
|
{{ module }}.wkt_f = new OpenLayers.Format.WKT();
|
||||||
|
{{ module }}.is_collection = {% if is_collection %}true{% else %}false{% endif %};
|
||||||
|
{{ module }}.collection_type = '{{ collection_type }}';
|
||||||
|
{{ module }}.is_linestring = {% if is_linestring %}true{% else %}false{% endif %};
|
||||||
|
{{ module }}.is_polygon = {% if is_polygon %}true{% else %}false{% endif %};
|
||||||
|
{{ module }}.is_point = {% if is_point %}true{% else %}false{% endif %};
|
||||||
|
{% endblock %}
|
||||||
|
{{ module }}.get_ewkt = function(feat){return 'SRID={{ srid }};' + {{ module }}.wkt_f.write(feat);}
|
||||||
|
{{ module }}.read_wkt = function(wkt){
|
||||||
|
// OpenLayers cannot handle EWKT -- we make sure to strip it out.
|
||||||
|
// EWKT is only exposed to OL if there's a validation error in the admin.
|
||||||
|
var match = {{ module }}.re.exec(wkt);
|
||||||
|
if (match){wkt = match[1];}
|
||||||
|
return {{ module }}.wkt_f.read(wkt);
|
||||||
|
}
|
||||||
|
{{ module }}.write_wkt = function(feat){
|
||||||
|
if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}
|
||||||
|
else { {{ module }}.num_geom = 1;}
|
||||||
|
document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);
|
||||||
|
}
|
||||||
|
{{ module }}.add_wkt = function(event){
|
||||||
|
// This function will sync the contents of the `vector` layer with the
|
||||||
|
// WKT in the text field.
|
||||||
|
if ({{ module }}.is_collection){
|
||||||
|
var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
|
||||||
|
for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){
|
||||||
|
feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
|
||||||
|
}
|
||||||
|
{{ module }}.write_wkt(feat);
|
||||||
|
} else {
|
||||||
|
// Make sure to remove any previously added features.
|
||||||
|
if ({{ module }}.layers.vector.features.length > 1){
|
||||||
|
old_feats = [{{ module }}.layers.vector.features[0]];
|
||||||
|
{{ module }}.layers.vector.removeFeatures(old_feats);
|
||||||
|
{{ module }}.layers.vector.destroyFeatures(old_feats);
|
||||||
|
}
|
||||||
|
{{ module }}.write_wkt(event.feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ module }}.modify_wkt = function(event){
|
||||||
|
if ({{ module }}.is_collection){
|
||||||
|
if ({{ module }}.is_point){
|
||||||
|
{{ module }}.add_wkt(event);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// When modifying the selected components are added to the
|
||||||
|
// vector layer so we only increment to the `num_geom` value.
|
||||||
|
var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
|
||||||
|
for (var i = 0; i < {{ module }}.num_geom; i++){
|
||||||
|
feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
|
||||||
|
}
|
||||||
|
{{ module }}.write_wkt(feat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{{ module }}.write_wkt(event.feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Function to clear vector features and purge wkt from div
|
||||||
|
{{ module }}.deleteFeatures = function(){
|
||||||
|
{{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);
|
||||||
|
{{ module }}.layers.vector.destroyFeatures();
|
||||||
|
}
|
||||||
|
{{ module }}.clearFeatures = function (){
|
||||||
|
{{ module }}.deleteFeatures();
|
||||||
|
document.getElementById('{{ id }}').value = '';
|
||||||
|
{{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
|
||||||
|
}
|
||||||
|
// Add Select control
|
||||||
|
{{ module }}.addSelectControl = function(){
|
||||||
|
var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});
|
||||||
|
{{ module }}.map.addControl(select);
|
||||||
|
select.activate();
|
||||||
|
}
|
||||||
|
{{ module }}.enableDrawing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();}
|
||||||
|
{{ module }}.enableEditing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();}
|
||||||
|
// Create an array of controls based on geometry type
|
||||||
|
{{ module }}.getControls = function(lyr){
|
||||||
|
{{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});
|
||||||
|
var nav = new OpenLayers.Control.Navigation();
|
||||||
|
var draw_ctl;
|
||||||
|
if ({{ module }}.is_linestring){
|
||||||
|
draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'});
|
||||||
|
} else if ({{ module }}.is_polygon){
|
||||||
|
draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'});
|
||||||
|
} else if ({{ module }}.is_point){
|
||||||
|
draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'});
|
||||||
|
}
|
||||||
|
{% if modifiable %}
|
||||||
|
var mod = new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'});
|
||||||
|
{{ module }}.controls = [nav, draw_ctl, mod];
|
||||||
|
{% else %}
|
||||||
|
{{ module }}.controls = [nav, darw_ctl];
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
{{ module }}.init = function(){
|
||||||
|
{% block map_options %}// The options hash, w/ zoom, resolution, and projection settings.
|
||||||
|
var options = {
|
||||||
|
{% autoescape off %}{% for item in map_options.items %} '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %}
|
||||||
|
{% endfor %}{% endautoescape %} };{% endblock %}
|
||||||
|
// The admin map for this geometry field.
|
||||||
|
{{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
|
||||||
|
// Base Layer
|
||||||
|
{{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS( "{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'} );{% endblock %}
|
||||||
|
{{ module }}.map.addLayer({{ module }}.layers.base);
|
||||||
|
{% block extra_layers %}{% endblock %}
|
||||||
|
{% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
|
||||||
|
{{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}");
|
||||||
|
{{ module }}.map.addLayer({{ module }}.layers.vector);
|
||||||
|
// Read WKT from the text field.
|
||||||
|
var wkt = document.getElementById('{{ id }}').value;
|
||||||
|
if (wkt){
|
||||||
|
// After reading into geometry, immediately write back to
|
||||||
|
// WKT <textarea> as EWKT (so that SRID is included).
|
||||||
|
var admin_geom = {{ module }}.read_wkt(wkt);
|
||||||
|
{{ module }}.write_wkt(admin_geom);
|
||||||
|
if ({{ module }}.is_collection){
|
||||||
|
// If geometry collection, add each component individually so they may be
|
||||||
|
// edited individually.
|
||||||
|
for (var i = 0; i < {{ module }}.num_geom; i++){
|
||||||
|
{{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{{ module }}.layers.vector.addFeatures([admin_geom]);
|
||||||
|
}
|
||||||
|
// Zooming to the bounds.
|
||||||
|
{{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());
|
||||||
|
} else {
|
||||||
|
{{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
|
||||||
|
}
|
||||||
|
// This allows editing of the geographic fields -- the modified WKT is
|
||||||
|
// written back to the content field (as EWKT, so that the ORM will know
|
||||||
|
// to transform back to original SRID).
|
||||||
|
{{ module }}.layers.vector.events.on({"featuremodified" : {{ module }}.modify_wkt});
|
||||||
|
{{ module }}.layers.vector.events.on({"featureadded" : {{ module }}.add_wkt});
|
||||||
|
{% block controls %}
|
||||||
|
// Map controls:
|
||||||
|
// Add geometry specific panel of toolbar controls
|
||||||
|
{{ module }}.getControls({{ module }}.layers.vector);
|
||||||
|
{{ module }}.panel.addControls({{ module }}.controls);
|
||||||
|
{{ module }}.map.addControl({{ module }}.panel);
|
||||||
|
{{ module }}.addSelectControl();
|
||||||
|
// Then add optional visual controls
|
||||||
|
{% if mouse_position %}{{ module }}.map.addControl(new OpenLayers.Control.MousePosition());{% endif %}
|
||||||
|
{% if scale_text %}{{ module }}.map.addControl(new OpenLayers.Control.Scale());{% endif %}
|
||||||
|
{% if layerswitcher %}{{ module }}.map.addControl(new OpenLayers.Control.LayerSwitcher());{% endif %}
|
||||||
|
// Then add optional behavior controls
|
||||||
|
{% if scrollable %}{% else %}{{ module }}.map.getControlsByClass('OpenLayers.Control.Navigation')[0].disableZoomWheel();{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
if (wkt){
|
||||||
|
{{ module }}.enableEditing();
|
||||||
|
} else {
|
||||||
|
{{ module }}.enableDrawing();
|
||||||
|
}
|
||||||
|
}
|
2
django/contrib/gis/templates/gis/admin/osm.html
Normal file
2
django/contrib/gis/templates/gis/admin/osm.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{% extends "gis/admin/openlayers.html" %}
|
||||||
|
{% block openlayers %}{% include "gis/admin/osm.js" %}{% endblock %}
|
2
django/contrib/gis/templates/gis/admin/osm.js
Normal file
2
django/contrib/gis/templates/gis/admin/osm.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{% extends "gis/admin/openlayers.js" %}
|
||||||
|
{% block base_layer %}new OpenLayers.Layer.OSM.Mapnik("OpenStreetMap (Mapnik)");{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user