| | 1 | [[TOC]] |
| | 2 | = How to use the GIS API within an application = |
| | 3 | This mini guide will show you how to use the GIS code in an Eden Application to display a map. The features that will be developed include: |
| | 4 | * A map of the zoomed into the area of interest |
| | 5 | * Markers displayed on the map for each point of interest |
| | 6 | * A pop-up displaying additional information when a marker is clicked |
| | 7 | * Multiple map layers which can be selected and deselected by the user |
| | 8 | The code for this guide is taken from the survey module and can be found (at the time or writing in the controllers/survey.py/series_map() function |
| | 9 | == Displaying the map == |
| | 10 | The display of the map is done with the show_map function |
| | 11 | {{{ |
| | 12 | #!div style="font-size: 80%" |
| | 13 | Code highlighting: |
| | 14 | {{{#!python |
| | 15 | map = gis.show_map() |
| | 16 | output["map"] = map |
| | 17 | }}} |
| | 18 | }}} |
| | 19 | This will create a map and place it in a map container that has been added to the view. The relevant part of the view is as follows: |
| | 20 | {{{ |
| | 21 | <div class='survey_map-container'> |
| | 22 | {{try:}} |
| | 23 | {{=map}} |
| | 24 | {{except:}} |
| | 25 | {{pass}} |
| | 26 | </div> |
| | 27 | }}} |
| | 28 | This will display a plain map at the default zoom level. The next task will be to add some markers. |
| | 29 | == Adding the markers == |
| | 30 | The API supports two mechanisms to add markers. The first is a simple list of latitude and longitude points. This is the features parameter and it adds non-interactive points. For the survey application interactive points were required and to the slightly more complex feature_queries parameter is required. |
| | 31 | The first step is to create a query that will hold all of the points that are to be displayed. The code for this is as follows: |
| | 32 | {{{ |
| | 33 | #!div style="font-size: 80%" |
| | 34 | Code highlighting: |
| | 35 | {{{#!python |
| | 36 | ctable = db.survey_complete |
| | 37 | atable = db.survey_answer |
| | 38 | gtable = db.gis_location |
| | 39 | |
| | 40 | series_name = response.s3.survey_getSeriesFromID(series_id) |
| | 41 | question_id = response.s3.survey_getLocationQuestionsIDForSeries(series_id) |
| | 42 | |
| | 43 | query = (atable.question_id == question_id) & \ |
| | 44 | (ctable.series_id == series_id) & \ |
| | 45 | (atable.complete_id == ctable.id ) & \ |
| | 46 | (atable.value == gtable.name) |
| | 47 | |
| | 48 | response_locations = db(query).select(atable.complete_id, |
| | 49 | gtable.uuid, |
| | 50 | gtable.id, |
| | 51 | gtable.name, |
| | 52 | gtable.lat, |
| | 53 | gtable.lon, |
| | 54 | ) |
| | 55 | }}} |
| | 56 | }}} |
| | 57 | The above is a query which links several tables together, the series_id has been passed into the function. The name of the series and the question_id are obtained from calls to functions defined in the model. The linking of the tables requires the series_id and the question_id, it then retrieves data from the gis_location table. |
| | 58 | Fully understanding this specific query is not essential to understanding how to add markers what is important is that you need construct a query that will return basic data from the gis_location table. The next step is to set up the features_query parameter, which can be done as follows: |
| | 59 | {{{ |
| | 60 | #!div style="font-size: 80%" |
| | 61 | Code highlighting: |
| | 62 | {{{#!python |
| | 63 | feature_queries.append({ "name": "%s: Assessments" % series_name, |
| | 64 | "query": response_locations, |
| | 65 | "active": True }) |
| | 66 | }}} |
| | 67 | }}} |
| | 68 | This will create a layer with the name of the series_name and points that were set up by the query stored in response_locations. The active of true means that the layer will be turned on by default. |
| | 69 | |
| | 70 | Finally the feature layer needs to be added to the call to show_map() |
| | 71 | {{{ |
| | 72 | #!div style="font-size: 80%" |
| | 73 | Code highlighting: |
| | 74 | {{{#!python |
| | 75 | map = gis.show_map(feature_queries = feature_queries) |
| | 76 | }}} |
| | 77 | }}} |
| | 78 | == Adding colour to the marker == |
| | 79 | Some basic colour and shape can be added to the marker. These are added by extending the details returned by the query. A shape, size of the shape and colour of the shape can be added as follows: |
| | 80 | {{{ |
| | 81 | #!div style="font-size: 80%" |
| | 82 | Code highlighting: |
| | 83 | {{{#!python |
| | 84 | response_colour_code = {-1:"#888888", # grey |
| | 85 | 0:"#000080", # blue |
| | 86 | 1:"#008000", # green |
| | 87 | 2:"#FFFF00", # yellow |
| | 88 | 3:"#FFA500", # orange |
| | 89 | 4:"#FF0000", # red |
| | 90 | 5:"#880088", # purple |
| | 91 | } |
| | 92 | if len(response_locations) > 0: |
| | 93 | for i in range( 0 , len( response_locations) ): |
| | 94 | complete_id = response_locations[i].survey_answer.complete_id |
| | 95 | response_locations[i].shape = "circle" |
| | 96 | response_locations[i].size = 5 |
| | 97 | priority = analysisTool.priority(complete_id) |
| | 98 | response_locations[i].colour = response_colour_code[priority] |
| | 99 | }}} |
| | 100 | }}} |
| | 101 | This will add small circular markers which are coloured depending upon a priority, which has been calculated by the call to analysisTool.priority(complete_id), again exactly how this works (and how the analysisTool object is created is not an important detail. The key is how the values are added to the response_location variable. |
| | 102 | |
| | 103 | The shapes that are currently supported are defined in the gis_feature_query() function in models/03_gis.py as follows: |
| | 104 | {{{ |
| | 105 | "circle", "square", "star", "x", "cross", "triangle" |
| | 106 | }}} |
| | 107 | The markers have now been added but when they are displayed because it is still using the default zoom they have probably been merged into a single cluster marker. |
| | 108 | == Zooming in to the required bounds == |
| | 109 | When multiple markers appear at the same location they are grouped together and replaced by a single cluster marker. If the zoom level is changed then more of the markers may take a unique location on the map and will be displayed using the feature marker. |
| | 110 | The bounds of the map can be calculated by calling the get_bounds() function as follows: |
| | 111 | {{{ |
| | 112 | #!div style="font-size: 80%" |
| | 113 | Code highlighting: |
| | 114 | {{{#!python |
| | 115 | bounds = gis.get_bounds(response_locations.records) |
| | 116 | }}} |
| | 117 | }}} |
| | 118 | This is then passed to the show_map function as follows: |
| | 119 | {{{ |
| | 120 | #!div style="font-size: 80%" |
| | 121 | Code highlighting: |
| | 122 | {{{#!python |
| | 123 | map = gis.show_map(feature_queries = feature_queries, |
| | 124 | bbox = bounds, |
| | 125 | ) |
| | 126 | }}} |
| | 127 | }}} |
| | 128 | == Adding a pop-up == |
| | 129 | The final feature to be added to the map is when clicking on the marker a pop-up appears displaying additional data. This is similar to the code that adds the marker and is placed in the same loop. The specific code is as follows: |
| | 130 | {{{ |
| | 131 | #!div style="font-size: 80%" |
| | 132 | Code highlighting: |
| | 133 | {{{#!python |
| | 134 | url = URL(c="survey", |
| | 135 | f="series", |
| | 136 | args=[series_id, |
| | 137 | "complete", |
| | 138 | complete_id, |
| | 139 | "read" |
| | 140 | ] |
| | 141 | ) |
| | 142 | response_locations[i].popup_url = url |
| | 143 | response_locations[i].popup_label = response_locations[i].gis_location.name |
| | 144 | }}} |
| | 145 | }}} |
| | 146 | Again the details of the url is not important although it is important to have a url that will return data suitable for an ajax call. |