| 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. |