-
Notifications
You must be signed in to change notification settings - Fork 1.1k
GNIP 26 Load Layers to a Map without GetCapabilities Requests
When loading layers on a map, GeoNode should store/retrieve all necessary information in its own Layer model rather than query GeoServer’s WMS GetCapabilities document. When adding GeoNode layers to a map, use Geonetwork’s data search functionality rather than GeoExt’s WMSGetCapabilitiesStore to list available layers.
Matt Bertrand
TBD.
Implemented in WorldMap; needs to be modified/integrated with more universal ‘Lazy Load’ functionality in gxp code.
Relying on WMS GetCapabilities to add or load layers in a map causes performance problems as the number of layers stored in a WMS server increases. Requests for the GetCapabilities document may time out, preventing the map’s layers from being loaded, or may cause ‘Script not responding’ warning messages to display in the browser. Bypassing the need to query the GetCapabilities document would improve performance and scalability.
Much of the information required for displaying layers on a map is already stored in GeoNode’s Layer model. The following additional fields should be added to the model:
srs = models.CharField(_('SRS'), max_length=24, blank=True, null=True, default="EPSG:4326")
bbox = models.TextField(_('bbox'), blank=True, null=True)
llbbox = models.TextField(_('llbbox'), blank=True, null=True)
Alternatively, the pre-existing ‘geographic_bounding_box’ field could be used instead of ‘srs’ and ‘llbox’, though in that case it should probably be removed from the layer’s edit form in GeoNode.
These fields can be populated with calls to GeoServer’s REST API via gsconfig.py:
self.srs = gs_resource.projection
self.bbox = str([float(gs_resource.native_bbox[0]),float(gs_resource.native_bbox[2]),float(gs_resource.native_bbox[1]),float(gs_resource.native_bbox[3])])
self.llbbox = str([float(gs_resource.latlon_bbox[0]),float(gs_resource.latlon_bbox[2]),float(gs_resource.latlon_bbox[1]),float(gs_resource.latlon_bbox[3])])
if self.geographic_bounding_box is '' or self.geographic_bounding_box is None:self.set_bbox(gs_resource.native_bbox, srs=self.srs)
GeoNode currently uses a MapLayer.layer_config function for layers that are already saved as part of a map. This function should be modified to retrieve additional fields from the Layer model:
gnLayer = Layer.objects.filter(typename=self.name)
if gnLayer.count() == 1:
if gnLayer[0].srs: cfg['srs'] = gnLayer[0].srs
if gnLayer[0].bbox: cfg['bbox'] = simplejson.loads(gnLayer[0].bbox)
if gnLayer[0].llbbox: cfg['llbbox'] = simplejson.loads(gnLayer[0].llbbox)
A similar layer_config function should be added to the Layer model and called when adding a new GeoNode layer to a map:
def layer_config(self, user):
cfg = dict()
cfg['name'] = self.typename
cfg['title'] =self.title
cfg['transparent'] = True
if self.topic_category:
cfg['group'] = self.topic_category.title
else:
cfg['group'] = 'General'
cfg['url'] = settings.GEOSERVER_BASE_URL + "wms"
cfg['srs'] = self.srs
cfg['bbox'] = simplejson.loads(self.bbox)
cfg['llbbox'] = simplejson.loads(self.llbbox)
cfg['queryable'] = (self.storeType == 'dataStore'),
cfg['disabled'] = user and not user.has_perm('maps.view_layer', obj=self)
cfg['visibility'] = True
cfg['abstract'] = self.abstract
cfg['styles'] = ''
return cfg
In WorldMap, a new gxp javascript object type was created, ‘GeoNodeSource’, that extends WMSSource. This object calculates the ‘maxExtent’ property from the ‘llbbox’ attribute returned by the Layer or MapLayer layer_config function, and adds ‘tileSize’ and ‘tileOrigin’ properties based on the global extent of the EPSG:900913 projection. One weakness of this approach is that it assumes that WorldMap/GeoNode will always use the 900913 projection for its maps. The code for GeoNodeSource is here:
https://github.com/cga-harvard/gxp/blob/master/src/script/plugins/GeoNodeSource.js
Tim Schaub has been working on an alternative approach, using a ‘Lazy Load’ function that will check to see if all required layer information is already present, and only retrieve the GetCapabilities document if there is anything missing. This lazy load capability could be used for remote WMS layers in addition to local GeoNode layers, and should probably replace/supercede the GeoNodeSource object.
Currently, GeoNode uses GeoExt’s WMSGetCapabilitiesStore, which requires a GetCapabilities request, to display a list of available layers to add to a map. This could be replaced with the existing data search interface, which queries Geonetwork for available layers and allows filtering by map extent and keywords:
Some slight modifications are necessary to the interface to add selected layers to the map without reloading the page. A new function in GeoExplorer.js is used to add passed layers to the map via an ajax call to return all the required parameters from Layer.layer_config():