select location from map
This commit is contained in:
parent
d9632dc0c4
commit
0b44acc8b0
7 changed files with 163 additions and 31 deletions
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue