wiki:DeveloperGuidelines/GIS

Version 50 (modified by Fran Boon, 8 years ago) ( diff )

Some updates to the 'Add New Layer Type' tutorial

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,
              height = None,
              width = None,
              bbox = {},
              lat = None,
              lon = None,
              zoom = None,
              projection = None,
              add_feature = False,
              add_feature_active = False,
              add_polygon = False,
              add_polygon_active = False,
              features = [],
              feature_queries = [],
              wms_browser = {},
              catalogue_layers = False,
              catalogue_toolbar = False,
              legend = False,
              toolbar = False,
              search = False,
              googleEarth = False,
              googleStreetview = False,
              mouse_position = "normal",
              print_tool = {},
              mgrs = {},
              window = False,
              window_hide = False,
              closable = True,
              collapsed = False,
              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 height: Height of viewport (if not provided then the default setting from the Map Service Catalogue is used)
        @param width: Width of viewport (if not provided then the default setting from the Map Service Catalogue is used)
        @param bbox: default Bounding Box of viewport (if not provided then the Lat/Lon/Zoom are used) (Dict):
            {
            "max_lat" : float,
            "max_lon" : float,
            "min_lat" : float,
            "min_lon" : 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)
            [{
                lat: lat,
                lon: lon
            }]
        @param feature_queries: Feature Queries to overlay onto the map & their options (List of Dicts):
            [{
             name   : "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_distance       # Optional
             cluster_threshold      # Optional
            }]
        @param wms_browser: WMS Server's GetCapabilities & options (dict)
            {
            name: string,           # Name for the Folder in LayerTree
            url: string             # URL of GetCapabilities
            }
        @param catalogue_overlays: Show the Overlays from the GIS Catalogue (@ToDo: make this a dict of which external overlays to allow)
        @param catalogue_toolbar: Show the Catalogue Toolbar
        @param legend: Show the Legend panel
        @param toolbar: Show the Icon Toolbar of Controls
        @param search: Show the Geonames search box
        @param mouse_position: Show the current coordinates in the bottom-right of the map. 3 Options: 'normal' (default), 'mgrs' (MGRS), False (off)
        @param print_tool: Show a print utility (NB This requires server-side support: http://eden.sahanafoundation.org/wiki/BluePrintGISPrinting)
            {
            url: string,            # URL of print service (e.g. http://localhost:8080/geoserver/pdf/)
            mapTitle: string        # Title for the Printed Map (optional)
            subTitle: string        # subTitle for the Printed Map (optional)
            }
        @param mgrs: Use the MGRS Control to select PDFs
            {
            name: string,           # Name for the Control
            url: string             # URL of PDF server
            }
        @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 public_url: pass from model (not yet defined when Module instantiated
    """

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.