Cómo mostrar los datos utilizando openlayers con OpenStreetMap en geodjango?
-
05-09-2019 - |
Pregunta
He conseguido geodjango ejecutan utilizando openlayers y OpenStreetMaps con la aplicación de administración.
Ahora quiero escribir algunos puntos de vista para mostrar los datos. Básicamente, sólo quiero añadir una lista de puntos (visto en el administrador) en el mapa.
Geodjango parece utilizar un especial archivo openlayers.js hacer su magia en el admin. ¿Hay una buena manera de interactuar con esto?
¿Cómo puedo escribir una vista / plantilla para mostrar los datos geodjango en una ventana de mapa de la calle abierta, como se ve en el administrador?
Por el momento, estoy cavando en el openlayers.js archivo y api en busca de una solución 'fácil' . (No tengo experiencia js así que esto está tomando algún tiempo.)
La forma actual que puedo ver de hacer esto es añadir lo siguiente como una plantilla, y el uso de Django para añadir el código necesario para mostrar los puntos. (Basado en el ejemplo aquí )
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Draw Feature Example</title>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(layer);
/*
* Layer style
*/
// we want opaque external graphics and non-opaque internal graphics
var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 1;
/*
* Blue style
*/
var style_blue = OpenLayers.Util.extend({}, layer_style);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
style_blue.graphicName = "star";
style_blue.pointRadius = 10;
style_blue.strokeWidth = 3;
style_blue.rotation = 45;
style_blue.strokeLinecap = "butt";
var vectorLayer = new OpenLayers.Layer.Vector("Simple Geometry", {style: layer_style});
// create a point feature
var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
var pointFeature = new OpenLayers.Feature.Vector(point,null,style_blue);
// Add additional points/features here via django
map.addLayer(vectorLayer);
map.setCenter(new OpenLayers.LonLat(point.x, point.y), 5);
vectorLayer.addFeatures([pointFeature]);
}
</script>
</head>
<body onload="init()">
<div id="map" class="smallmap"></div>
</body>
</html>
¿Es así como se hace, o hay una mejor manera?
Solución
Creo que la solución es viable y, probablemente, el método más sencillo. Sólo crear plantillas de la javascript y usar Django para inyectar sus puntos de datos como la plantilla se representa.
Si desea obtener más elegante, usted podría tener una vista de Django que sirven los puntos de datos como JSON (application / json) y luego usar AJAX para devolver la llamada y recuperar los datos en función de los acontecimientos que están sucediendo en el navegador. Si desea que su aplicación sea muy interactiva más allá de lo OpenLayers ofrece, esto podría valer la pena la complejidad añadida, pero por supuesto que todo depende de las necesidades de su aplicación.
Otros consejos
Otra solución es crear un formulario que utiliza el widget GeoDjango de administración.
Para ello, I:
Configuración de un GeneratePolygonAdminClass:
class GeneratePolygonAdmin(admin.GeoModelAdmin):
list_filter=('polygon',)
list_display=('object', 'polygon')
Cuando el formulario se construyó:
geoAdmin=GeneratePolygonAdmin(ModelWithPolygonField, admin.site)
PolygonFormField=GeneratePolygon._meta.get_field('Polygon')
PolygonWidget=geoAdmin.get_map_widget(PolygonFormField)
Dict['Polygon']=forms.CharField(widget=PolygonWidget()) #In this case, I am creating a Dict to use for a dynamic form
Rellenar el widget de la forma:
def SetupPolygonWidget(form, LayerName, MapFileName, DefaultPolygon=''):
form.setData({'Polygon':DefaultPolygon})
form.fields['Polygon'].widget.params['wms_layer']=LayerName
form.fields['Polygon'].widget.params['wms_url']='/cgi-bin/mapserv?MAP=' + MapFileName
form.fields['Polygon'].widget.params['default_lon']=-80.9
form.fields['Polygon'].widget.params['default_lat']=33.7
form.fields['Polygon'].widget.params['default_zoom']=11
form.fields['Polygon'].widget.params['wms_name']=YOURWMSLayerName
form.fields['Polygon'].widget.params['map_width']=800
form.fields['Polygon'].widget.params['map_height']=600
form.fields['Polygon'].widget.params['map_srid']=YOUR_SRID
form.fields['Polygon'].widget.params['modifiable']=True
form.fields['Polygon'].widget.params['map_options']={}
form.fields['Polygon'].widget.params['map_options']['buffer'] = 0
return form
Basado en el código en: http: // code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980
Parece que se puede utilizar la opción de incluir extra_js OpenStreetMap (no he probado esto).
Esto es bastante antiguo, y yo no iría en torno a la creación de una plantilla de hackear como yo pensaba originalmente. Ahora me gustaría utilizar leaflet.js con una petición AJAX a una vista de Django que devuelve GeoJSON a un folleto capa GeoJSON.
Esto hace que el lado Django muy fácil.
Muestra Django Ver:
# -*- coding: utf-8 -*-
'''
'''
import json
from django.http import HttpResponse, HttpResponseBadRequest
from django.contrib.gis.geos import Polygon
from models import ResultLayer, MyModel
def get_layer_polygons(request, layer_id):
"""
Return the polygons for the given bbox (bounding box)
"""
layer = ResultLayer.objects.get(id=layer_id)
bbox_raw = request.GET.get("bbox", None)
# Make sure the incoming bounding box is correctly formed!
bbox = None
if bbox_raw and bbox_raw.count(",") == 3:
bbox = [float(v) for v in bbox_raw.split(",")]
if not bbox:
msg = "Improperly formed or not given 'bbox' querystring option, should be in the format '?bbox=minlon,minlat,maxlon,maxlat'"
return HttpResponseBadRequest(msg)
bbox_poly = Polygon.from_bbox(bbox)
bbox_poly.srid = 900913 # google
bbox_poly.transform(layer.srid) # transform to the layer's srid for querying
bin_size = int(bin_size)
# build vector polygons from bin
results = MyModel.objects.filter(layer=layer, poly__intersects=bbox_poly).transform(900913, field_name="poly")
geojson_data = []
for r in results:
# loading json in order to dump json list later
gjson = r.poly.geojson
py_gjson = json.loads(gjson)
geojson_data.append(py_gjson)
return HttpResponse(json.dumps(geojson_data), mimetype='application/json')
Se podría considerar el uso FloppyForms . Al final, por lo general terminan la personalización de la solución a mis propias necesidades, pero es una buena manera de empezar.
Pedido este tutorial del proyecto geodjango-basic-aplicaciones:
http://code.google.com/p/geodjango-basic-apps / wiki / FOSS4GWorkshop
tal vez usted no tiene que cortar su propio Javascript todavía