select location from map

This commit is contained in:
Laura Klünder 2016-12-20 22:20:42 +01:00
parent d9632dc0c4
commit 0b44acc8b0
7 changed files with 163 additions and 31 deletions

View file

@ -292,7 +292,7 @@ class PointLocation(Location):
def subtitle(self) -> str:
return 'Coordinates'
def to_location_json(self):
def to_json(self):
result = super().to_location_json()
result['level'] = self.level.name
result['x'] = self.x

View file

@ -1,4 +1,5 @@
from calendar import timegm
from collections import OrderedDict
from functools import wraps
from django.core.cache import cache
@ -90,7 +91,7 @@ class CachedReadOnlyViewSetMixin():
@cache_result('c3nav__mapdata__levels')
def get_levels_cached():
from c3nav.mapdata.models import Level
return {level.name: level for level in Level.objects.all()}
return OrderedDict((level.name, level) for level in Level.objects.all())
@cache_result('c3nav__mapdata__packages')

View file

@ -44,6 +44,9 @@ body, .btn {
.locationselect .icons .link {
background-image:url('../img/icons/link.svg');
}
.locationselect .icons .map {
background-image:url('../img/icons/map.svg');
}
.location-group .only-if-selected {
display:none;
@ -52,6 +55,39 @@ body, .btn {
display:block;
}
.locationselect-map {
display:none;
position:relative;
}
.location-group.map .locationselect-map {
display:block;
}
.location-group.map .locationselect-input {
display:none;
}
.locationselect-map .map-container {
width:100%;
overflow:auto;
height:200px;
position:relative;
}
.locationselect-map .map-container img, .locationselect-map .map-container input {
position:absolute;
left:0;
top:0;
}
.locationselect-map .map-buttons {
position:absolute;
top:8px;
left:8px;
}
.locationselect-map .scroll-hint {
color:#FFFFFF;
position:absolute;
top:150px;
left:16px;
}
.location {
font-size:18px;

View file

@ -1,6 +1,10 @@
c3nav = {
init: function() {
if (!$('.main-view').length) return;
c3nav.main_view = $('.main-view');
if (!c3nav.main_view.length) return;
c3nav.svg_width = parseInt(c3nav.main_view.attr('data-svg-width'));
c3nav.svg_height = parseInt(c3nav.main_view.attr('data-svg-height'));
c3nav._typeahead_locations = new Bloodhound({
datumTokenizer: function(data) {
@ -33,6 +37,10 @@ c3nav = {
c3nav.locationselect_focus();
$('.locationselect .icons .reset').click(c3nav._locationselect_reset);
$('.locationselect .icons .map').click(c3nav._locationselect_activate_map);
$('.locationselect .close-map').click(c3nav._locationselect_close_map);
$('.locationselect .level-selector a').click(c3nav._locationselect_click_level);
$('.locationselect .map-container').on('click', 'img', c3nav._locationselect_click_image);
$('#route-from-here').click(c3nav._click_route_from_here);
$('#route-to-here').click(c3nav._click_route_to_here);
@ -47,6 +55,49 @@ c3nav = {
location_group.find('.tt-suggestion').remove();
c3nav._locations_changed();
},
_locationselect_activate_map: function(e) {
e.preventDefault();
var location_group = $(this).closest('.location-group');
location_group.addClass('map');
var map_container = location_group.find('.map-container');
console.log(c3nav.svg_height-(map_container.height()/2));
map_container.scrollTop((c3nav.svg_height-map_container.height())/2).scrollLeft((c3nav.svg_width-map_container.width())/2);
location_group.find('.level-selector a').first().click();
},
_locationselect_close_map: function(e) {
e.preventDefault();
var location_group = $(this).closest('.location-group');
location_group.removeClass('map').find('.tt-input').focus();
},
_locationselect_click_level: function(e) {
e.preventDefault();
var location_group = $(this).closest('.location-group');
var map_container = location_group.find('.map-container');
var level = $(this).attr('data-level');
map_container.find('img').remove();
map_container.append($('<img>').attr({
'src': '/map/'+level+'.png',
'width': c3nav.svg_width,
'height': c3nav.svg_height
}));
map_container.attr('data-level', level);
},
_locationselect_click_image: function(e) {
var level = $(e.delegateTarget).attr('data-level');
var coords = 'c:'+level+':'+parseInt(e.offsetX/6*100)+':'+parseInt(e.offsetY/6*100);
var location_group = $(this).closest('.location-group');
location_group.removeClass('map').addClass('selected');
var selected = location_group.find('.locationselect-selected');
selected.find('.title').text('');
selected.find('.subtitle').text('');
selected.find('.id-field').val(coords);
$.getJSON('/api/locations/'+coords, function(data) {
selected.find('.title').text(data.title);
selected.find('.subtitle').text(data.subtitle);
});
c3nav._locations_changed();
c3nav.locationselect_focus();
},
locationselect_focus: function() {
$('.location-group:visible:not(.selected) .locationselect-input .tt-input').first().focus();
},
@ -59,7 +110,7 @@ c3nav = {
},
_click_route_x_here: function(e, location_group) {
e.preventDefault();
$('.main-view').removeClass('mode-location').addClass('mode-route');
c3nav.main_view.removeClass('mode-location').addClass('mode-route');
from_group = $('.location-select');
from_group.removeClass('selected');
location_group.addClass('selected').find('.id-field').val(from_group.find('.id-field').val());
@ -107,8 +158,9 @@ c3nav = {
_locations_changed: function(e) {
var url;
if ($('.main-view').is('.mode-location')) {
url = '/l/'+$(':input[name=location]').val()+'/';
if (c3nav.main_view.is('.mode-location')) {
var location = $(':input[name=location]').val()
url = (location !== '') ? '/l/'+location+'/' : '/';
} else {
var origin = $(':input[name=origin]').val();
var destination = $(':input[name=destination]').val();

View file

@ -1,5 +1,5 @@
{% load i18n %}
<div class="col-md-{% if name == 'location' %}12{% else %}6{% endif %} location-group {{ name }}-select{% if location %} selected{% endif %}">
<div class="col-md-{% if name == 'location' %}12{% else %}6{% endif %} location-group {{ name }}-select{% if location %} selected{% endif %}{% if active_field == name and map_level %} map{% endif %}">
<div class="form-group{% if search == name and not search_results %} has-error{% endif %}" data-name="{{ name }}">
<label for="{{ name }}_input">{{ heading }}</label>
<div class="locationselect">
@ -23,6 +23,27 @@
</div>
</span>
{% endif %}
<div class="icons">
<a href="?map-level={{ levels.0 }}" class="map"></a>
</div>
</div>
<div class="locationselect-map">
<div class="map-container">
<div class="dummy" style="width:{{ svg_width }}px;height:{{ svg_height }}px;"></div>
{% if map_level %}
<input type="image" src="/map/{{ map_level }}.png" width="{{ svg_width }}" height="{{ svg_height }}">
<p class="scroll-hint">{% trans 'You have Javascript deactivated. Please scroll in this direction ⇘' %}</p>
{% endif %}
</div>
<div class="map-buttons">
<div class="btn-group level-selector" role="group">
{% for level in levels %}
<a href="?map-level={{ level }}" data-level="{{ level }}" class="btn btn-default{% if level == map_level %} active{% endif %}">{{ level }}</a>
{% endfor %}
</div>
<a href="?" class="btn btn-default close-map">{% trans 'close' %}</a>
</div>
<span class="help-block">{% trans 'Click or tap the desired location on the map.' %}</span>
</div>
<div class="locationselect-selected">
<div class="location form-control input-lg">
@ -52,7 +73,7 @@
</div>
</div>
{% endif %}
{% if not location %}
{% if not location and not map_level %}
<noscript>
<button type="submit" class="btn btn-primary btn-block">{% trans 'Search' %}</button>
</noscript>

View file

@ -4,7 +4,7 @@
{% load i18n %}
{% block content %}
<form method="post" class="main-view mode-{{ mode }}{% if origin and destination %} can-route{% endif %}">
<form method="post" class="main-view mode-{{ mode }}{% if origin and destination %} can-route{% endif %}" data-svg-width="{{ svg_width }}" data-svg-height="{{ svg_height }}">
{% csrf_token %}
<div class="row locations">
{% trans "Location" as heading %}

View file

@ -1,7 +1,7 @@
from datetime import timedelta
from django.http import Http404
from django.shortcuts import get_object_or_404, render
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
@ -9,6 +9,7 @@ from c3nav.mapdata.models import Level
from c3nav.mapdata.models.locations import get_location, search_location
from c3nav.mapdata.permissions import get_excludables_includables
from c3nav.mapdata.render.compose import composer
from c3nav.mapdata.utils.cache import get_levels_cached
from c3nav.mapdata.utils.misc import get_dimensions
from c3nav.routing.graph import Graph
@ -49,38 +50,68 @@ def main(request, location=None, origin=None, destination=None):
mode = 'location' if not origin and not destination else 'route'
active_field = None
if not origin and not destination:
active_field = 'location'
elif origin and not destination:
active_field = 'destination'
elif destination and not origin:
active_field = 'origin'
ctx = {
'location': location,
'origin': origin,
'destination': destination,
'mode': mode,
'active_field': active_field,
}
search = None
if not origin and not destination:
search = 'location'
elif origin and not destination:
search = 'destination'
elif destination and not origin:
search = 'origin'
width, height = get_dimensions()
levels = tuple(name for name, level in get_levels_cached().items() if not level.intermediate)
if search is not None:
search_query = request.POST.get(search+'_search', '').strip() or None
ctx.update({
'width': width,
'height': height,
'svg_width': int(width * 6),
'svg_height': int(height * 6),
'levels': levels,
})
map_level = request.GET.get('map-level')
if map_level in levels:
ctx.update({
'map_level': map_level
})
if 'x' in request.POST and 'y' in request.POST:
x = request.POST.get('x')
y = request.POST.get('y')
if x.isnumeric() and y.isnumeric():
coords = 'c:%s:%d:%d' % (map_level, int(int(x)/6*100), int(int(y)/6*100))
if active_field == 'origin':
return redirect('site.route', origin=coords, destination=destination.location_id)
elif active_field == 'destination':
return redirect('site.route', origin=origin.location_id, destination=coords)
elif active_field == 'location':
return redirect('site.location', location=coords)
if active_field is not None:
search_query = request.POST.get(active_field+'_search', '').strip() or None
if search_query:
results = search_location(request, search_query)
url = 'site.location' if search == 'location' else 'site.route'
url = 'site.location' if active_field == 'location' else 'site.route'
kwargs = {}
if origin:
kwargs['origin'] = origin.location_id
if destination:
kwargs['destination'] = destination.location_id
for result in results:
kwargs[search] = result.location_id
kwargs[active_field] = result.location_id
result.url = reverse(url, kwargs=kwargs)
ctx.update({
'search': search,
'search': active_field,
'search_query': search_query,
'search_results': results,
})
@ -159,15 +190,6 @@ def main(request, location=None, origin=None, destination=None):
'route': route,
})
width, height = get_dimensions()
ctx.update({
'width': width,
'height': height,
'svg_width': width*6,
'svg_height': height*6,
})
response = render(request, 'site/main.html', ctx)
if request.method == 'POST' and save_settings: