wiki:DeveloperGuidelines/GIS

Version 52 (modified by somayjain, 7 years ago) ( diff )

--

GIS Module

We use OpenLayers to display Maps with some GeoExt widgets.

Guidelines for Developers wishing to make use of Mapping within their Module

The easiest approach is to call the Mapping API.

Controller

map = gis.show_map()
return dict(map=map)

View

{{=XML(map)}}

Examples

Check the following functions in controllers/gis.py:

  • map_viewing_client()
  • display_feature()
  • display_features()

Full API description

def show_map( self,
              id = "default_map",
              height = None,
              width = None,
              bbox = {},
              lat = None,
              lon = None,
              zoom = None,
              projection = None,
              add_feature = False,
              add_feature_active = False,
              add_line = False,
              add_line_active = False,
              add_polygon = False,
              add_polygon_active = False,
              features = None,
              feature_queries = None,
              feature_resources = None,
              wms_browser = {},
              catalogue_layers = False,
              legend = False,
              toolbar = False,
              area = False,
              nav = None,
              save = False,
              search = False,
              mouse_position = None,
              overview = None,
              permalink = None,
              scaleline = None,
              zoomcontrol = None,
              zoomWheelEnabled = True,
              mgrs = {},
              window = False,
              window_hide = False,
              closable = True,
              maximizable = True,
              collapsed = False,
              callback = "DEFAULT",
              plugins = None,
              ):
    """
        Returns the HTML to display a map

        Normally called in the controller as: map = gis.show_map()
        In the view, put: {{=XML(map)}}

        @param id: ID to uniquely identify this map if there are several on a page
        @param height: Height of viewport (if not provided then the default deployment setting is used)
        @param width: Width of viewport (if not provided then the default deployment setting is used)
        @param bbox: default Bounding Box of viewport (if not provided then the Lat/Lon/Zoom are used) (Dict):
            {"lon_min" : float,
             "lat_min" : float,
             "lon_max" : float,
             "lat_max" : float,
             }
        @param lat: default Latitude of viewport (if not provided then the default setting from the Map Service Catalogue is used)
        @param lon: default Longitude of viewport (if not provided then the default setting from the Map Service Catalogue is used)
        @param zoom: default Zoom level of viewport (if not provided then the default setting from the Map Service Catalogue is used)
        @param projection: EPSG code for the Projection to use (if not provided then the default setting from the Map Service Catalogue is used)
        @param add_feature: Whether to include a DrawFeature control to allow adding a marker to the map
        @param add_feature_active: Whether the DrawFeature control should be active by default
        @param add_polygon: Whether to include a DrawFeature control to allow drawing a polygon over the map
        @param add_polygon_active: Whether the DrawFeature control should be active by default
        @param features: Simple Features to overlay on Map (no control over appearance & not interactive)
            [wkt]
        @param feature_queries: Feature Queries to overlay onto the map & their options (List of Dicts):
            [{"name"   : T("MyLabel"), # A string: the label for the layer
              "query"  : query,        # A gluon.sql.Rows of gis_locations, which can be from a simple query or a Join.
                                       # Extra fields can be added for 'popup_url', 'popup_label' & either
                                       # 'marker' (url/height/width) or 'shape' (with optional 'colour' & 'size')
              "active" : True,         # Is the feed displayed upon load or needs ticking to load afterwards?
              "marker" : None,         # Optional: A per-Layer marker query or marker_id for the icon used to display the feature
              "opacity" : 1,           # Optional
              "cluster_attribute",     # Optional
              "cluster_distance",      # Optional
              "cluster_threshold"      # Optional
            }]
        @param feature_resources: REST URLs for (filtered) resources to overlay onto the map & their options (List of Dicts):
            [{"name"      : T("MyLabel"), # A string: the label for the layer
              "id"        : "search",     # A string: the id for the layer (for manipulation by JavaScript)
              "active"    : True,         # Is the feed displayed upon load or needs ticking to load afterwards?
              EITHER:
              "layer_id"  : 1,            # An integer: the layer_id to load (optional alternative to specifying URL/tablename/marker)
              "filter"    : "filter",     # A string: an optional URL filter which *replaces* any in the layer
              OR:
              "tablename" : "module_resource", # A string: the tablename (used to determine whether to locate via location_id or site_id)
              "url"       : "/eden/module/resource.geojson?filter", # A URL to load the resource

              "marker"    : None,         # Optional: A per-Layer marker dict for the icon used to display the feature (overrides layer_id if-set)
              "opacity"   : 1,            # Optional (overrides layer_id if-set)
              "cluster_attribute",        # Optional (overrides layer_id if-set)
              "cluster_distance",         # Optional (overrides layer_id if-set)
              "cluster_threshold",        # Optional (overrides layer_id if-set)
              "dir",                      # Optional (overrides layer_id if-set)
              "style",                    # Optional (overrides layer_id if-set)
            }]
        @param wms_browser: WMS Server's GetCapabilities & options (dict)
            {"name": T("MyLabel"),     # Name for the Folder in LayerTree
             "url": string             # URL of GetCapabilities
            }
        @param catalogue_layers: Show all the enabled Layers from the GIS Catalogue
                                 Defaults to False: Just show the default Base layer
        @param legend: True: Show the GeoExt Legend panel, False: No Panel, "float": New floating Legend Panel
        @param toolbar: Show the Icon Toolbar of Controls
        @param area: Show the Area tool on the Toolbar
        @param nav: Show the Navigation controls on the Toolbar
        @param save: Show the Save tool on the Toolbar
        @param search: Show the Geonames search box (requires a username to be configured)
        @param mouse_position: Show the current coordinates in the bottom-right of the map. 3 Options: 'normal', 'mgrs', False (defaults to checking deployment_settings, which defaults to 'normal')
        @param overview: Show the Overview Map (defaults to checking deployment_settings, which defaults to True)
        @param permalink: Show the Permalink control (defaults to checking deployment_settings, which defaults to True)
        @param scaleline: Show the ScaleLine control (defaults to checking deployment_settings, which defaults to True)
        @param zoomcontrol: Show the Zoom control (defaults to checking deployment_settings, which defaults to True)
        @param mgrs: Use the MGRS Control to select PDFs
            {"name": string,           # Name for the Control
             "url": string             # URL of PDF server
            }
            @ToDo: Also add MGRS Search support: http://gxp.opengeo.org/master/examples/mgrs.html
        @param window: Have viewport pop out of page into a resizable window
        @param window_hide: Have the window hidden by default, ready to appear (e.g. on clicking a button)
        @param closable: In Window mode, whether the window is closable or not
        @param collapsed: Start the Tools panel (West region) collapsed
        @param callback: Code to run once the Map JavaScript has loaded
        @param plugins: an iterable of objects which support the following methods:
                            .extend_gis_map(map)
                        Client-side portion suppoprts the following methods:
                            .addToMapWindow(items)
                            .setup(map)
    """

Variable Markers

Example:

query = (db.gis_location.deleted == False)
query = query & (db.gis_location.id == db["%s_%s" % (module, resource)].location_id)
locations = db(query).select(db.gis_location.id, db.gis_location.uuid, db.gis_location.name, db.gis_location.wkt, db.gis_location.lat, db.gis_location.lon)
for i in range(0, len(locations)):
    locations[i].gis_location.shape = "circle"
    locations[i].gis_location.size = locations[i][db["%s_%s" % (module, resource)].MyIntegerField]

Guidelines for Developers wishing to extend the functionality of the core GIS

OpenLayers

The GIS module uses OpenLayers for Display purposes, so a thorough understanding of this is a great foundation for what we do:

Projections: http://trac.openlayers.org/wiki/Documentation/Dev/proj4js

Debugging advice: http://docs.openlayers.org/help/minimize.html

GUI

The map window is wrapped in an Ext GUI based on GeoExt (formerly MapFish client)

How to debug WMS

How to add a new Layer type

Assuming that OpenLayers supports the layertype:

Model

modules/s3db/gis.py

_gis_layer_types = ["newlayertype", "..."]
table = self.define_table("gis_layer_newlayertype",
                          name_field(),
                          Field("description", label=T("Description")),
                          Field("enabled", "boolean", default=True, label=T("Available in Viewer?")),
                          Field("visible", "boolean", default=True,
                                label=T("On by default? (only applicable to Overlays)")),
                          Field("url", label=T("Location"), requires = IS_NOT_EMPTY(),
                                comment=DIV(_class="tooltip",
                                            _title="%s|%s" % (T("Location"),
                                                              T("The URL to access the service.")))),
                          Field("version", length=32,
                                label=T("Version"), default="1.1.1",
                                requires=IS_IN_SET(["1.1.1", "1.3.0"], zero=None)),
                          Field("base", "boolean", default=False,
                                label=T("Base Layer?")),
                          Field("transparent", "boolean", default=True,
                                label=T("Transparent?")),
                          gis_opacity(),
                          role_required(),       # Single Role
                          #roles_permitted(),    # Multiple Roles (needs implementing in modules/s3gis.py)
                          *s3_timestamp())

Controller

controllers/gis.py

def layer_newlayertype():
    """ RESTful CRUD controller """
    if settings.get_security_map() and not s3_has_role("MapAdmin"):
        unauthorised()

    resourcename = request.function
    tablename = "%s_%s" % (module, resourcename)
    table = s3db[tablename]

    # Model options
    table.url.comment = SPAN("*", _class="req")

    # CRUD Strings
    type = "New Layer Type"
    LAYERS = T(TYPE_LAYERS_FMT % type)
    ADD_NEW_LAYER = T(ADD_NEW_TYPE_LAYER_FMT % type)
    EDIT_LAYER = T(EDIT_TYPE_LAYER_FMT % type)
    LIST_LAYERS = T(LIST_TYPE_LAYERS_FMT % type)
    NO_LAYERS = T(NO_TYPE_LAYERS_FMT % type)
    s3.crud_strings[tablename] = Storage(
        title_create=ADD_LAYER,
        title_display=LAYER_DETAILS,
        title_list=LAYERS,
        title_update=EDIT_LAYER,
        title_search=SEARCH_LAYERS,
        subtitle_create=ADD_NEW_LAYER,
        subtitle_list=LIST_LAYERS,
        label_list_button=LIST_LAYERS,
        label_create_button=ADD_LAYER,
        label_delete_button = DELETE_LAYER,
        msg_record_created=LAYER_ADDED,
        msg_record_modified=LAYER_UPDATED,
        msg_record_deleted=LAYER_DELETED,
        msg_list_empty=NO_LAYERS)

    # Post-processor
    def postp(r, output):
        s3_action_buttons(r)
        return output
    response.s3.postp = postp

    output = s3_rest_controller()

    if not "gis" in response.view:
        response.view = "gis/" + response.view

    return output

View

views/gis/map_service_catalogue.html

<li><a href='{{=URL(f="layer_newlayertype")}}'>New Layer Type</a> - Description</li>

Module

Classes need adding: modules/s3gis.py

class NewTypeLayer(Layer):
...

def show_map():
for LayerType in [
                  ...
                  NewTypeLayer,

Static

OpenLayers code needs adding: static/scripts/S3/s3.gis.layers.js

function addNewTyppeLayer(layer) {
    ...
}
function addLayers() {
    ....
    if (S3.gis.layers_newlayertype) {
        for (i = 0; i < S3.gis.layers_newlayertype.length; i++) {
            addNewTypeLayer(S3.gis.layers_newlayertype[i]);
        }
    }
    ....
}
cd static/scripts/tools
build gis

See Also

DeveloperGuidelines

Note: See TracWiki for help on using the wiki.