Как отображать данные с помощью openlayers с OpenStreetMap в geodjango?
-
05-09-2019 - |
Вопрос
У меня работает geodjango, используя открытые слои и OpenStreetMaps с приложением администратора.
Теперь я хочу написать несколько представлений для отображения данных.По сути, я просто хочу добавить на карту список точек (видимый в админке).
Геоджанго, похоже, использует особенный openlayers.js файл, чтобы сделать это волшебство в админке.Есть ли хороший способ взаимодействия с этим?
Как я могу написать представление/шаблон для отображения данных геоджанго в открытом окне карты улиц, как это видно в администраторе?
На данный момент я копаюсь в openlayers.js file и API ищут «простое» решение.(У меня нет опыта работы с JS, поэтому это займет некоторое время.)
В настоящее время я вижу, что это можно сделать следующим образом: добавить в качестве шаблона следующий код и использовать django для добавления кода, необходимого для отображения точек.(На примере здесь)
<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>
Так это делается или есть лучший способ?
Решение
Я думаю, что ваше решение работоспособно и, вероятно, самое простое.Просто создайте шаблон JavaScript и используйте Django для ввода точек данных по мере визуализации шаблона.
Если вы хотите пофантазировать, вы могли бы создать представление Django, которое предоставляло бы точки данных в формате JSON (application/json), а затем использовало AJAX для обратного вызова и получения данных на основе событий, происходящих в браузере.Если вы хотите, чтобы ваше приложение было более интерактивным, чем то, что предоставляет OpenLayers, возможно, это стоит дополнительных сложностей, но, конечно, все зависит от потребностей вашего приложения.
Другие советы
Другое решение — создать форму, использующую виджет администратора GeoDjango.
Для этого я:
Настройте GeneratePolygonAdminClass:
class GeneratePolygonAdmin(admin.GeoModelAdmin):
list_filter=('polygon',)
list_display=('object', 'polygon')
Где создается форма:
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
Заполнение виджета формы:
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
На основе кода по адресу:http://code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980
Похоже, вы можете использовать опцию extra_js, чтобы включить OpenStreetMap (я это не проверял).
Это довольно старая версия, и я бы не стал создавать хак шаблона, как я изначально думал.Сейчас я бы использовал листовка.js с запросом ajax к представлению django, которое возвращает geojson в слой geojson листовки.
Это делает работу с Джанго очень простой.
Пример представления Django:
# -*- 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')
Вы можете рассмотреть возможность использования FloppyForms.В конце концов, я обычно настраиваю решение под свои нужды, но это хороший способ начать.
Ознакомьтесь с этим руководством из проекта geodjango-basic-apps:
http://code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop
возможно, вам пока не нужно взламывать свой собственный JavaScript