diff --git a/flask_project/campaign_manager/templates/campaign_detail.html b/flask_project/campaign_manager/templates/campaign_detail.html
index 93f468fc6..d994053af 100644
--- a/flask_project/campaign_manager/templates/campaign_detail.html
+++ b/flask_project/campaign_manager/templates/campaign_detail.html
@@ -200,7 +200,9 @@
-
+
+ {% include 'campaign_detail/map.html' %}
+
@@ -354,6 +356,51 @@
});
}
+ function addMapElements(activeType) {
+ var url_vt = "{{ s3_campaign_url | safe }}/render/" + activeType + "/tiles/{z}/{x}/{y}.pbf";
+
+ map.addSource('tiles', {
+ "type": "vector",
+ "minzoom": 10,
+ "maxzoom": 17,
+ "tiles": [url_vt]
+ });
+
+ map.addLayer({
+ "id": "campaign-polygons",
+ "type": "fill",
+ "source": "tiles",
+ "source-layer": "campaign",
+ "filter": ["in", "$type", "Polygon"],
+ "paint": {
+ "fill-color": ['get', 'completeness_color'],
+ "fill-opacity": 1
+ }
+ });
+ map.addLayer({
+ "id": "campaign-lines",
+ "type": "line",
+ "source": "tiles",
+ "source-layer": "campaign",
+ "filter": ["in", "$type", "LineString"],
+ "paint": {
+ "line-color": ['get', 'completeness_color'],
+ "line-opacity": 0.7
+ }
+ });
+ map.addLayer({
+ "id": "campaign-points",
+ "type": "circle",
+ "source": "tiles",
+ "source-layer": "campaign",
+ "filter": ["in", "$type", "Point"],
+ "paint": {
+ "circle-color": ['get', 'completeness_color'],
+ }
+ });
+
+ }
+
function loadType(activeType, s3CampaignUrl) {
activeType = activeType.replace(/ /g, '_')
var typeUrl = getTypeUrl(activeType, s3CampaignUrl);
@@ -379,23 +426,28 @@
$('.content-wrapper').html(data);
});
- $.get({
- url: typeUrl + 'map.html',
- cache: false
- }).then(function(data) {
- $('.map-wrapper').html(data)
- });
-
- $.get({
- url: typeUrl + 'errors.html',
- cache: false
- }).then(function(data) {
- $('.errors-wrapper').html(data)
- });
+ $.get({
+ url: typeUrl + 'errors.html',
+ cache: false
+ }).then(function(data) {
+ $('.errors-wrapper').html(data)
+ });
+
+ window.setTimeout(function() {
+ setMapHeight();
+ }, 2000);
+
+ // Load data into map.
+ let source = map.getSource('tiles');
+
+ if (typeof source !== 'undefined') {
+ map.removeLayer("campaign-polygons");
+ map.removeLayer("campaign-lines");
+ map.removeLayer("campaign-points");
+ map.removeSource('tiles');
+ }
- window.setTimeout(function() {
- setMapHeight();
- }, 2000);
+ addMapElements(activeType);
}
diff --git a/flask_project/campaign_manager/templates/campaign_detail/map.html b/flask_project/campaign_manager/templates/campaign_detail/map.html
new file mode 100644
index 000000000..28e14d1ab
--- /dev/null
+++ b/flask_project/campaign_manager/templates/campaign_detail/map.html
@@ -0,0 +1,136 @@
+
+
+ Completeness
+ 100%
+ 75%
+ 50%
+ 25%
+ 0%
+
+
+
+
\ No newline at end of file
diff --git a/flask_project/campaign_manager/utilities.py b/flask_project/campaign_manager/utilities.py
index a2fd15741..b292a7192 100644
--- a/flask_project/campaign_manager/utilities.py
+++ b/flask_project/campaign_manager/utilities.py
@@ -24,7 +24,9 @@
from campaign_manager.models.survey import Survey
from glob import glob
+from datetime import datetime
+import xml.etree.ElementTree as ET
def module_path(*args):
"""Get an absolute path for a file that is relative to the root.
@@ -344,3 +346,38 @@ def get_contribs(url, ctype):
data = [item for sublist in data for item in sublist]
return data
+
+
+def geojson_to_gpx(geojson):
+ root = ET.Element(
+ "gpx",
+ attrib=dict(
+ xmlns="http://www.topografix.com/GPX/1/1",
+ version="1.1",
+ creator="HOT MapCampaigner",
+ ),
+ )
+ # Create GPX Metadata element
+ metadata = ET.Element("metadata")
+ link = ET.SubElement(
+ metadata,
+ "link",
+ attrib={'href': "https://github.com/hotosm/mapcampaigner"},
+ )
+ ET.SubElement(link, "text").text = "HOT MapCampaigner"
+ ET.SubElement(metadata, "time").text = datetime.today().isoformat()
+ root.append(metadata)
+ # Create trk element
+ trk = ET.Element("trk")
+ root.append(trk)
+
+ trkseg = ET.SubElement(trk, "trkseg")
+ for coord in geojson['geometry']['coordinates'][0]:
+ coord_dict = dict(lon=str(coord[0]), lat=str(coord[1]))
+ ET.SubElement(trkseg, "trkpt", attrib=coord_dict,)
+
+ # Append wpt elements to end of doc
+ wpt = ET.Element("wpt", attrib=coord_dict)
+ root.append(wpt)
+
+ return ET.tostring(root, encoding="utf8")
diff --git a/flask_project/campaign_manager/views.py b/flask_project/campaign_manager/views.py
index 550c1b0b5..f2f0f4ad5 100644
--- a/flask_project/campaign_manager/views.py
+++ b/flask_project/campaign_manager/views.py
@@ -1,3 +1,4 @@
+import base64
import csv
import inspect
import json
@@ -46,7 +47,7 @@
from campaign_manager.data_providers.overpass_provider import OverpassProvider
from reporter import config
from campaign_manager.utilities import (
- load_osm_document_cached, get_contribs
+ load_osm_document_cached, get_contribs, geojson_to_gpx
)
from reporter import LOGGER
from reporter.static_files import static_file
@@ -54,6 +55,7 @@
from xml.sax.saxutils import escape
+
try:
from secret import OAUTH_CONSUMER_KEY, OAUTH_SECRET
except ImportError:
@@ -437,6 +439,25 @@ def participate():
abort(404)
+@campaign_manager.route('/gpx/', methods=['GET'])
+def generate_gpx(json_data):
+ # decoding to geojson
+ try:
+ decoded_json = base64.b64decode(json_data).decode('utf-8')
+ except UnicodeDecodeError:
+ abort(400)
+
+ geojson = json.loads(decoded_json)
+ xml_gpx = geojson_to_gpx(geojson)
+
+ resp = Response(xml_gpx, mimetype='text/xml', status=200)
+
+ # Disable CORS.
+ resp.headers['Access-Control-Allow-Origin'] = '*'
+
+ return resp
+
+
@campaign_manager.route('/generate_josm', methods=['POST'])
def generate_josm():
"""Get overpass xml data from ids store it to temporary folder."""