feature: add map of all people

This commit is contained in:
James Graham
2020-12-16 14:54:46 +00:00
parent 1a27774177
commit b2cd5f4940
7 changed files with 111 additions and 27 deletions

View File

@@ -74,6 +74,10 @@
<a href="{% url 'activities:activity.list' %}" class="nav-link">Activities</a> <a href="{% url 'activities:activity.list' %}" class="nav-link">Activities</a>
</li> </li>
<li class="nav-item">
<a href="{% url 'people:person.map' %}" class="nav-link">Map</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a href="{% url 'people:network' %}" class="nav-link">Network</a> <a href="{% url 'people:network' %}" class="nav-link">Network</a>
</li> </li>

View File

@@ -10,17 +10,26 @@ const marker_label_offset = 0.27 * marker_scale;
const marker_edge_alpha = 1.0; const marker_edge_alpha = 1.0;
const marker_edge_width = 1.0; const marker_edge_width = 1.0;
let map = null
// The function called when Google Maps starts up // The function called when Google Maps starts up
function initMap() { function initMap() {
const centre_latlng = new google.maps.LatLng(settings.centre_lat, settings.centre_lng); // const centre_latlng = new google.maps.LatLng(settings.centre_lat, settings.centre_lng);
// The map, centered at Soton // The map, centered at Soton
const map = new google.maps.Map( map = new google.maps.Map(
document.getElementById('map'), { zoom: settings.zoom, center: centre_latlng }); // document.getElementById('map'), { zoom: settings.zoom, center: centre_latlng });
document.getElementById('map'));
const bounds = new google.maps.LatLngBounds()
const markers_data = JSON.parse(
document.getElementById('map-markers').textContent
).filter(data => data.lat !== null && data.lng !== null);
// For each data entry in the json... // For each data entry in the json...
for (const pin_data of data) { for (const pin_data of markers_data) {
// Get the lat-long position from the data // Get the lat-long position from the data
const lat_lng = new google.maps.LatLng(pin_data.lat, pin_data.lng); const lat_lng = new google.maps.LatLng(pin_data.lat, pin_data.lng);
console.log(lat_lng)
// Generate a new marker // Generate a new marker
const marker = new google.maps.Marker({ const marker = new google.maps.Marker({
@@ -38,6 +47,10 @@ function initMap() {
}, },
}); });
console.log(marker)
bounds.extend(marker.position)
// Build the info window content to tell the user the last time it was visited. // Build the info window content to tell the user the last time it was visited.
marker.info = new google.maps.InfoWindow({ marker.info = new google.maps.InfoWindow({
content: "<div id='content'>" + content: "<div id='content'>" +
@@ -56,6 +69,25 @@ function initMap() {
}) })
} }
map.fitBounds(bounds)
const max_zoom = 10
if (map.getZoom() > max_zoom) {
map.setZoom(max_zoom)
}
// Set the last info window to null // Set the last info window to null
var last_info = null; var last_info = null;
setTimeout(setMaxZoom, 100)
}
/**
* Zoom to set level if map is zoomed in more than this.
*/
function setMaxZoom() {
const max_zoom = 10
if (map.getZoom() > max_zoom) {
map.setZoom(max_zoom)
}
} }

View File

@@ -1,23 +1,9 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block extra_head %} {% block extra_head %}
{{ map_markers|json_script:'map-markers' }}
{% load staticfiles %} {% load staticfiles %}
<script type="application/javascript">
const data = [
{
name: '{{ person.name }}',
lat: '{{ answer_set.latitude }}',
lng: '{{ answer_set.longitude }}'
},
]
const settings = {
zoom: 8,
centre_lat: '{{ answer_set.latitude }}',
centre_lng: '{{ answer_set.longitude }}',
}
</script>
<script src="{% static 'js/map.js' %}"></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" <script async defer src="https://maps.googleapis.com/maps/api/js?key={{ settings.GOOGLE_MAPS_API_KEY }}&callback=initMap"

View File

@@ -42,13 +42,6 @@
</tr> </tr>
{% endif %} {% endif %}
{% if answer_set.latitude and answer_set.longitude %}
<tr>
<td>Location</td>
<td>{{ answer_set.latitude }}, {{ answer_set.longitude }}</td>
</tr>
{% endif %}
{% for answer in answer_set.question_answers.all %} {% for answer in answer_set.question_answers.all %}
<tr> <tr>
<td>{{ answer.question }}</td> <td>{{ answer.question }}</td>

View File

@@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% block extra_head %}
{{ map_markers|json_script:'map-markers' }}
{% load staticfiles %}
<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">
<li class="breadcrumb-item">
<a href="{% url 'people:person.list' %}">People</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Map</li>
</ol>
</nav>
<h1>Map</h1>
<div id="map" style="height: 800px; width: 100%"></div>
{% endblock %}

View File

@@ -38,6 +38,10 @@ urlpatterns = [
views.relationship.RelationshipUpdateView.as_view(), views.relationship.RelationshipUpdateView.as_view(),
name='relationship.update'), name='relationship.update'),
path('map',
views.person.PersonMapView.as_view(),
name='person.map'),
path('network', path('network',
views.network.NetworkView.as_view(), views.network.NetworkView.as_view(),
name='network'), name='network'),

View File

@@ -5,6 +5,7 @@ Views for displaying or manipulating instances of :class:`Person`.
import typing import typing
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.views.generic import CreateView, DetailView, ListView, UpdateView from django.views.generic import CreateView, DetailView, ListView, UpdateView
@@ -61,6 +62,7 @@ class ProfileView(permissions.UserIsLinkedPersonMixin, DetailView):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['answer_set'] = self.object.current_answers context['answer_set'] = self.object.current_answers
context['map_markers'] = [get_map_data(self.object)]
return context return context
@@ -103,3 +105,38 @@ class PersonUpdateView(permissions.UserIsLinkedPersonMixin, UpdateView):
answer_set.save() answer_set.save()
return response return response
def get_map_data(person: models.Person) -> typing.Dict[str, typing.Any]:
answer_set = person.current_answers
try:
latitude = answer_set.latitude or None
longitude = answer_set.longitude or None
except AttributeError:
latitude = None
longitude = None
return {
'name': person.name,
'lat': latitude,
'lng': longitude,
'url': reverse('people:person.detail', kwargs={'pk': person.pk})
}
class PersonMapView(LoginRequiredMixin, ListView):
"""
View displaying a map of :class:`Person` locations.
"""
model = models.Person
template_name = 'people/person/map.html'
def get_context_data(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
context = super().get_context_data(**kwargs)
context['map_markers'] = [
get_map_data(person) for person in self.object_list
]
return context