mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 19:37:06 +00:00
feat: add initial map code from activity mapper
This commit is contained in:
@@ -94,6 +94,10 @@ The most likely required settings are: SECRET_KEY, DEBUG, ALLOWED_HOSTS, DATABAS
|
||||
- EMAIL_USE_SSL
|
||||
default: True if EMAIL_PORT == 465 else False
|
||||
Use SSL to communicate with SMTP server? Usually on port 465
|
||||
|
||||
- GOOGLE_MAPS_API_KEY
|
||||
default: None
|
||||
Google Maps API key to display maps of people's locations
|
||||
"""
|
||||
|
||||
import collections
|
||||
@@ -113,6 +117,7 @@ SETTINGS_EXPORT = [
|
||||
'DEBUG',
|
||||
'PROJECT_LONG_NAME',
|
||||
'PROJECT_SHORT_NAME',
|
||||
'GOOGLE_MAPS_API_KEY',
|
||||
]
|
||||
|
||||
PROJECT_LONG_NAME = config('PROJECT_LONG_NAME', default='Project Long Name')
|
||||
@@ -393,3 +398,7 @@ except ImportError as exc:
|
||||
CUSTOMISATION_NAME = None
|
||||
TEMPLATE_NAME_INDEX = 'index.html'
|
||||
TEMPLATE_WELCOME_EMAIL_NAME = 'welcome-email'
|
||||
|
||||
# Upstream API keys
|
||||
|
||||
GOOGLE_MAPS_API_KEY = config('GOOGLE_MAPS_API_KEY', default=None)
|
||||
|
||||
127
people/static/js/map.js
Normal file
127
people/static/js/map.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const marker_main_alpha_never = 1.0;
|
||||
const marker_main_alpha_future = 1.0;
|
||||
const marker_main_alpha = 1.0;
|
||||
|
||||
const marker_main_colour_never = 'grey';
|
||||
const marker_main_colour_future = 'white';
|
||||
|
||||
const marker_edge_colour = 'white';
|
||||
const marker_edge_colour_never = 'white';
|
||||
const marker_edge_colour_future = 'black';
|
||||
|
||||
|
||||
// Size of the arrow markers used on the map
|
||||
const marker_scale = 9;
|
||||
// Offset for the place type icon (multiplier for marker scale)
|
||||
const marker_label_offset = 0.27 * marker_scale;
|
||||
// Width and transparency for the edges of the markers
|
||||
const marker_edge_alpha = 1.0;
|
||||
const marker_edge_width = 1.0;
|
||||
|
||||
const settings = {
|
||||
zoom: 5
|
||||
}
|
||||
|
||||
// const data = [
|
||||
// {lat: 0, lng: 0, name: 'a'},
|
||||
// {lat: 1, lng: 1, name: 'b'},
|
||||
// {lat: 2, lng: 2, name: 'c'},
|
||||
// ]
|
||||
|
||||
|
||||
|
||||
// Pull settings from the settings var
|
||||
// const time_after = filters.time_after;
|
||||
// const time_before = filters.time_before;
|
||||
// Set up a colour scale that goes from blue to red via yellow, over time_limit days
|
||||
// const visitedColour = d3.scaleSequential(d3.interpolateRdYlBu)
|
||||
// .domain([filters.time_after, filters.time_before]);
|
||||
|
||||
|
||||
// The function called when Google Maps starts up
|
||||
function initMap() {
|
||||
const centre_latlng = new google.maps.LatLng(0, 0);
|
||||
// The map, centered at Soton
|
||||
const map = new google.maps.Map(
|
||||
document.getElementById('map'), { zoom: settings.zoom, center: centre_latlng });
|
||||
|
||||
// For each data entry in the json...
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
// Get the lat-long position from the data
|
||||
var lat_lng = new google.maps.LatLng(data[i].lat, data[i].lng);
|
||||
|
||||
// Generate a new marker
|
||||
var marker = new google.maps.Marker({
|
||||
position: lat_lng, map: map,
|
||||
icon: {
|
||||
path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW,
|
||||
strokeColor: edgeColourByTime(data[i]),
|
||||
strokeWeight: marker_edge_width,
|
||||
strokeOpacity: marker_edge_alpha,
|
||||
fillColor: mainColourByTime(data[i]),
|
||||
fillOpacity: alphaByTime(data[i]),
|
||||
scale: marker_scale,
|
||||
labelOrigin: new google.maps.Point(0, -marker_label_offset)
|
||||
},
|
||||
label: (data[i].type === 'school' ? '🎓' : '')
|
||||
});
|
||||
|
||||
// Build the info window content to tell the user the last time it was visited.
|
||||
marker.info = new google.maps.InfoWindow({
|
||||
content: "<div id='content'>" +
|
||||
"<h3><a href=" + data[i].url + ">" + data[i].name.replace(''', "'") + "</a></h3>" +
|
||||
(data[i].hasOwnProperty('lastvisit') ? "<p>Last visited " + data[i].lastvisit + "</p>" : "<p>Never visited</p>") +
|
||||
"</div>"
|
||||
});
|
||||
|
||||
// We bind a listener to the current marker so that if it's clicked, it checks for an open info window,
|
||||
// closes it, then opens the info window attached to it specifically. Then sets that as the last window.
|
||||
google.maps.event.addListener(marker, 'click', function () {
|
||||
if (last_info) {
|
||||
last_info.close();
|
||||
}
|
||||
last_info = this.info;
|
||||
this.info.open(map, this);
|
||||
})
|
||||
}
|
||||
|
||||
// Set the last info window to null
|
||||
var last_info = null;
|
||||
}
|
||||
|
||||
|
||||
function mainColourByTime(d) {
|
||||
if (!d.hasOwnProperty('time')) {
|
||||
return marker_main_colour_never;
|
||||
} else if (d.time > time_after) {
|
||||
return visitedColour(time_after);
|
||||
} else if (d.time < time_before) {
|
||||
return marker_main_colour_future;
|
||||
} else {
|
||||
return visitedColour(d.time);
|
||||
}
|
||||
}
|
||||
|
||||
function edgeColourByTime(d) {
|
||||
if (!d.hasOwnProperty('time')) {
|
||||
return marker_edge_colour_never;
|
||||
} else if (d.time > time_after) {
|
||||
return marker_edge_colour;
|
||||
} else if (d.time < time_before) {
|
||||
return marker_edge_colour_future;
|
||||
} else {
|
||||
return marker_edge_colour;
|
||||
}
|
||||
}
|
||||
|
||||
function alphaByTime(d) {
|
||||
if (!d.hasOwnProperty('time')) {
|
||||
return marker_main_alpha_never;
|
||||
} else if (d.time > time_after) {
|
||||
return marker_main_alpha;
|
||||
} else if (d.time < time_before) {
|
||||
return marker_main_alpha_future;
|
||||
} else {
|
||||
return marker_main_alpha;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% load staticfiles %}
|
||||
<script type="application/javascript">
|
||||
const data = [
|
||||
{name: 'Test Person', lat: 0, lng: 0},
|
||||
]
|
||||
</script>
|
||||
|
||||
<script src="{% static 'js/map.js' %}"></script>
|
||||
|
||||
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{ settings.GOOGLE_MAPS_API_KEY }}&callback=initMap"
|
||||
type="text/javascript"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
@@ -24,68 +38,7 @@
|
||||
|
||||
|
||||
{% with person.current_answers as answer_set %}
|
||||
<dl>
|
||||
</dl>
|
||||
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Question</th>
|
||||
<th>Answer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% if answer_set.nationality %}
|
||||
<tr><td>Nationality</td><td>{{ answer_set.nationality.name }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.country_of_residence %}
|
||||
<tr><td>Country of Residence</td><td>{{ answer_set.country_of_residence.name }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.organisation %}
|
||||
<tr><td>Organisation</td><td>{{ answer_set.organisation }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.organisation_started_date %}
|
||||
<tr><td>Organisation Started Date</td><td>{{ answer_set.organisation_started_date }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.job_title %}
|
||||
<tr><td>Job Title</td><td>{{ answer_set.job_title }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.disciplines %}
|
||||
<tr><td>Discipline(s)</td><td>{{ answer_set.disciplines }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.themes.exists %}
|
||||
<tr>
|
||||
<td>Project Themes</td>
|
||||
<td>
|
||||
{% for theme in answer_set.themes.all %}
|
||||
{{ theme }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% for answer in answer_set.question_answers.all %}
|
||||
<tr>
|
||||
<td>{{ answer.question }}</td>
|
||||
<td>{{ answer }}</td>
|
||||
</tr>
|
||||
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>No records</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>Last updated: {{ answer_set.timestamp }}</p>
|
||||
{% include 'people/person/includes/answer_set.html' %}
|
||||
{% endwith %}
|
||||
|
||||
<a class="btn btn-success"
|
||||
@@ -99,6 +52,10 @@
|
||||
|
||||
<hr>
|
||||
|
||||
<div id="map" style="height: 800px; width: 100%"></div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2>Relationships As Source</h2>
|
||||
@@ -207,3 +164,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_script %}
|
||||
{% endblock %}
|
||||
|
||||
59
people/templates/people/person/includes/answer_set.html
Normal file
59
people/templates/people/person/includes/answer_set.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Question</th>
|
||||
<th>Answer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% if answer_set.nationality %}
|
||||
<tr><td>Nationality</td><td>{{ answer_set.nationality.name }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.country_of_residence %}
|
||||
<tr><td>Country of Residence</td><td>{{ answer_set.country_of_residence.name }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.organisation %}
|
||||
<tr><td>Organisation</td><td>{{ answer_set.organisation }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.organisation_started_date %}
|
||||
<tr><td>Organisation Started Date</td><td>{{ answer_set.organisation_started_date }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.job_title %}
|
||||
<tr><td>Job Title</td><td>{{ answer_set.job_title }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.disciplines %}
|
||||
<tr><td>Discipline(s)</td><td>{{ answer_set.disciplines }}</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if answer_set.themes.exists %}
|
||||
<tr>
|
||||
<td>Project Themes</td>
|
||||
<td>
|
||||
{% for theme in answer_set.themes.all %}
|
||||
{{ theme }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% for answer in answer_set.question_answers.all %}
|
||||
<tr>
|
||||
<td>{{ answer.question }}</td>
|
||||
<td>{{ answer }}</td>
|
||||
</tr>
|
||||
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>No records</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>Last updated: {{ answer_set.timestamp }}</p>
|
||||
Reference in New Issue
Block a user