show nearby locations
This commit is contained in:
parent
3134829cc7
commit
27b35a384d
7 changed files with 68 additions and 19 deletions
|
@ -283,6 +283,7 @@ class CustomLocation:
|
||||||
('grid_square', self.grid_square),
|
('grid_square', self.grid_square),
|
||||||
('near_area', self.near_area.pk if self.near_area else None),
|
('near_area', self.near_area.pk if self.near_area else None),
|
||||||
('near_poi', self.near_poi.pk if self.near_poi else None),
|
('near_poi', self.near_poi.pk if self.near_poi else None),
|
||||||
|
('nearby', tuple(location.pk for location in self.nearby)),
|
||||||
('altitude', None if self.altitude is None else round(self.altitude, 2))
|
('altitude', None if self.altitude is None else round(self.altitude, 2))
|
||||||
))
|
))
|
||||||
if not grid.enabled:
|
if not grid.enabled:
|
||||||
|
@ -378,6 +379,10 @@ class CustomLocation:
|
||||||
def near_poi(self):
|
def near_poi(self):
|
||||||
return self.description.near_poi
|
return self.description.near_poi
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def nearby(self):
|
||||||
|
return self.description.nearby
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def grid_square(self):
|
def grid_square(self):
|
||||||
return grid.get_square_for_point(self.x, self.y) or ''
|
return grid.get_square_for_point(self.x, self.y) or ''
|
||||||
|
|
|
@ -363,15 +363,25 @@ class Router:
|
||||||
restrictions = self.get_restrictions(location.permissions)
|
restrictions = self.get_restrictions(location.permissions)
|
||||||
space = self.space_for_point(level=location.level.pk, point=location, restrictions=restrictions)
|
space = self.space_for_point(level=location.level.pk, point=location, restrictions=restrictions)
|
||||||
if not space:
|
if not space:
|
||||||
return CustomLocationDescription(space=space, altitude=None, areas=(), near_area=None, near_poi=None)
|
return CustomLocationDescription(space=space, altitude=None, areas=(), near_area=None, near_poi=None,
|
||||||
|
nearby=())
|
||||||
try:
|
try:
|
||||||
altitude = space.altitudearea_for_point(location).get_altitude(location)
|
altitude = space.altitudearea_for_point(location).get_altitude(location)
|
||||||
except LocationUnreachable:
|
except LocationUnreachable:
|
||||||
altitude = None
|
altitude = None
|
||||||
areas, near_area = space.areas_for_point(areas=self.areas, point=location, restrictions=restrictions)
|
areas, near_area, nearby_areas = space.areas_for_point(
|
||||||
near_poi = space.poi_for_point(pois=self.pois, point=location, restrictions=restrictions)
|
areas=self.areas, point=location, restrictions=restrictions
|
||||||
|
)
|
||||||
|
near_poi, nearby_pois = space.poi_for_point(
|
||||||
|
pois=self.pois, point=location, restrictions=restrictions
|
||||||
|
)
|
||||||
|
nearby = tuple(sorted(
|
||||||
|
tuple(l for l in nearby_areas+nearby_pois if l[0].can_search),
|
||||||
|
key=operator.itemgetter(1)
|
||||||
|
))[:20]
|
||||||
|
nearby = tuple(location for location, distance in nearby)
|
||||||
return CustomLocationDescription(space=space, altitude=altitude,
|
return CustomLocationDescription(space=space, altitude=altitude,
|
||||||
areas=areas, near_area=near_area, near_poi=near_poi)
|
areas=areas, near_area=near_area, near_poi=near_poi, nearby=nearby)
|
||||||
|
|
||||||
def shortest_path(self, restrictions, options):
|
def shortest_path(self, restrictions, options):
|
||||||
options_key = options.serialize_string()
|
options_key = options.serialize_string()
|
||||||
|
@ -482,7 +492,7 @@ class Router:
|
||||||
|
|
||||||
|
|
||||||
CustomLocationDescription = namedtuple('CustomLocationDescription', ('space', 'altitude',
|
CustomLocationDescription = namedtuple('CustomLocationDescription', ('space', 'altitude',
|
||||||
'areas', 'near_area', 'near_poi'))
|
'areas', 'near_area', 'near_poi', 'nearby'))
|
||||||
|
|
||||||
|
|
||||||
class BaseRouterProxy:
|
class BaseRouterProxy:
|
||||||
|
@ -535,26 +545,30 @@ class RouterSpace(BaseRouterProxy):
|
||||||
areas = {pk: area for pk, area in areas.items()
|
areas = {pk: area for pk, area in areas.items()
|
||||||
if pk in self.areas and area.can_describe and area.access_restriction_id not in restrictions}
|
if pk in self.areas and area.can_describe and area.access_restriction_id not in restrictions}
|
||||||
|
|
||||||
|
nearby = ((area, area.geometry.distance(point)) for area in areas.values())
|
||||||
|
nearby = tuple((area, distance) for area, distance in nearby if distance < 20)
|
||||||
|
|
||||||
contained = tuple(area for area in areas.values() if area.geometry_prep.contains(point))
|
contained = tuple(area for area in areas.values() if area.geometry_prep.contains(point))
|
||||||
if contained:
|
if contained:
|
||||||
return tuple(sorted(contained, key=lambda area: area.geometry.area)), None
|
return tuple(sorted(contained, key=lambda area: area.geometry.area)), None, nearby
|
||||||
|
|
||||||
near = ((area, area.geometry.distance(point)) for area in areas.values())
|
near = tuple((area, distance) for area, distance in nearby if distance < 5)
|
||||||
near = tuple((area, distance) for area, distance in near if distance < 5)
|
|
||||||
if not near:
|
if not near:
|
||||||
return (), None
|
return (), None, nearby
|
||||||
return (), min(near, key=operator.itemgetter(1))[0]
|
return (), min(near, key=operator.itemgetter(1))[0], nearby
|
||||||
|
|
||||||
def poi_for_point(self, pois, point, restrictions):
|
def poi_for_point(self, pois, point, restrictions):
|
||||||
point = Point(point.x, point.y)
|
point = Point(point.x, point.y)
|
||||||
pois = {pk: poi for pk, poi in pois.items()
|
pois = {pk: poi for pk, poi in pois.items()
|
||||||
if pk in self.pois and poi.can_describe and poi.access_restriction_id not in restrictions}
|
if pk in self.pois and poi.can_describe and poi.access_restriction_id not in restrictions}
|
||||||
|
|
||||||
near = ((poi, poi.geometry.distance(point)) for poi in pois.values())
|
nearby = ((poi, poi.geometry.distance(point)) for poi in pois.values())
|
||||||
near = tuple((poi, distance) for poi, distance in near if distance < 5)
|
nearby = tuple((poi, distance) for poi, distance in nearby if distance < 20)
|
||||||
|
|
||||||
|
near = tuple((poi, distance) for poi, distance in nearby if distance < 5)
|
||||||
if not near:
|
if not near:
|
||||||
return None
|
return None, nearby
|
||||||
return min(near, key=operator.itemgetter(1))[0]
|
return min(near, key=operator.itemgetter(1))[0], nearby
|
||||||
|
|
||||||
|
|
||||||
class RouterArea(BaseRouterProxy):
|
class RouterArea(BaseRouterProxy):
|
||||||
|
|
|
@ -213,13 +213,18 @@ c3nav = {
|
||||||
},
|
},
|
||||||
|
|
||||||
state: {},
|
state: {},
|
||||||
update_state: function(routing, replace, details, options) {
|
update_state: function(routing, replace, details, options, nearby) {
|
||||||
if (typeof routing !== "boolean") routing = c3nav.state.routing;
|
if (typeof routing !== "boolean") routing = c3nav.state.routing;
|
||||||
|
|
||||||
if (details) {
|
if (details) {
|
||||||
options = false;
|
options = false;
|
||||||
|
nearby = false;
|
||||||
} else if (options) {
|
} else if (options) {
|
||||||
details = false;
|
details = false;
|
||||||
|
nearby = false;
|
||||||
|
} else if (nearby) {
|
||||||
|
details = false;
|
||||||
|
options = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var destination = $('#destination-input').data('location'),
|
var destination = $('#destination-input').data('location'),
|
||||||
|
@ -230,7 +235,8 @@ c3nav = {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
sidebar: true,
|
sidebar: true,
|
||||||
details: !!details,
|
details: !!details,
|
||||||
options: !!options
|
options: !!options,
|
||||||
|
nearby: !!nearby,
|
||||||
};
|
};
|
||||||
|
|
||||||
c3nav._push_state(new_state, replace);
|
c3nav._push_state(new_state, replace);
|
||||||
|
@ -669,6 +675,9 @@ c3nav = {
|
||||||
if (state.details && (url.startsWith('/l/') || url.startsWith('/r/'))) {
|
if (state.details && (url.startsWith('/l/') || url.startsWith('/r/'))) {
|
||||||
url += 'details/'
|
url += 'details/'
|
||||||
}
|
}
|
||||||
|
if (state.nearby && url.startsWith('/l/')) {
|
||||||
|
url += 'nearby/'
|
||||||
|
}
|
||||||
if (state.options && url.startsWith('/r/')) {
|
if (state.options && url.startsWith('/r/')) {
|
||||||
url += 'options/'
|
url += 'options/'
|
||||||
}
|
}
|
||||||
|
@ -1212,6 +1221,7 @@ c3nav = {
|
||||||
L.Icon.Default.imagePath = '/static/leaflet/images/';
|
L.Icon.Default.imagePath = '/static/leaflet/images/';
|
||||||
c3nav._add_icon('origin');
|
c3nav._add_icon('origin');
|
||||||
c3nav._add_icon('destination');
|
c3nav._add_icon('destination');
|
||||||
|
c3nav._add_icon('nearby');
|
||||||
|
|
||||||
// setup scale control
|
// setup scale control
|
||||||
L.control.scale({imperial: false}).addTo(c3nav.map);
|
L.control.scale({imperial: false}).addTo(c3nav.map);
|
||||||
|
@ -1281,7 +1291,7 @@ c3nav = {
|
||||||
if (nearby) {
|
if (nearby) {
|
||||||
var $destination = $('#destination-input');
|
var $destination = $('#destination-input');
|
||||||
c3nav._locationinput_set($destination, data);
|
c3nav._locationinput_set($destination, data);
|
||||||
c3nav.update_state(false);
|
c3nav.update_state(false, false, false, false, true);
|
||||||
} else {
|
} else {
|
||||||
newpopup = L.popup(c3nav._add_map_padding({
|
newpopup = L.popup(c3nav._add_map_padding({
|
||||||
className: 'location-popup',
|
className: 'location-popup',
|
||||||
|
@ -1333,6 +1343,24 @@ c3nav = {
|
||||||
c3nav._visible_map_locations = [];
|
c3nav._visible_map_locations = [];
|
||||||
if (origin) c3nav._merge_bounds(bounds, c3nav._add_location_to_map(origin, single ? new L.Icon.Default() : c3nav.originIcon));
|
if (origin) c3nav._merge_bounds(bounds, c3nav._add_location_to_map(origin, single ? new L.Icon.Default() : c3nav.originIcon));
|
||||||
if (destination) c3nav._merge_bounds(bounds, c3nav._add_location_to_map(destination, single ? new L.Icon.Default() : c3nav.destinationIcon));
|
if (destination) c3nav._merge_bounds(bounds, c3nav._add_location_to_map(destination, single ? new L.Icon.Default() : c3nav.destinationIcon));
|
||||||
|
var done = [];
|
||||||
|
if (c3nav.state.nearby && destination && 'areas' in destination) {
|
||||||
|
if (destination.space) {
|
||||||
|
c3nav._merge_bounds(bounds, c3nav._add_location_to_map(c3nav.locations_by_id[destination.space], c3nav.nearbyIcon, true));
|
||||||
|
}
|
||||||
|
if (destination.near_area) {
|
||||||
|
done.push(destination.near_area);
|
||||||
|
c3nav._merge_bounds(bounds, c3nav._add_location_to_map(c3nav.locations_by_id[destination.near_area], c3nav.nearbyIcon, true));
|
||||||
|
}
|
||||||
|
for (var area of destination.areas) {
|
||||||
|
done.push(area);
|
||||||
|
c3nav._merge_bounds(bounds, c3nav._add_location_to_map(c3nav.locations_by_id[area], c3nav.nearbyIcon, true));
|
||||||
|
}
|
||||||
|
for (var location of destination.nearby) {
|
||||||
|
if (location in done) continue;
|
||||||
|
c3nav._merge_bounds(bounds, c3nav._add_location_to_map(c3nav.locations_by_id[location], c3nav.nearbyIcon, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
c3nav._locationLayerBounds = bounds;
|
c3nav._locationLayerBounds = bounds;
|
||||||
},
|
},
|
||||||
fly_to_bounds: function(replace_state, nofly) {
|
fly_to_bounds: function(replace_state, nofly) {
|
||||||
|
|
|
@ -8,12 +8,13 @@ slug = r'(?P<slug>[a-z0-9-_.:]+)'
|
||||||
coordinates = r'(?P<coordinates>[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)'
|
coordinates = r'(?P<coordinates>[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)'
|
||||||
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
|
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
|
||||||
details = r'(?P<details>details/)?'
|
details = r'(?P<details>details/)?'
|
||||||
|
nearby = r'(?P<nearby>nearby/)?'
|
||||||
options = r'(?P<options>options/)?'
|
options = r'(?P<options>options/)?'
|
||||||
pos = r'(@(?P<level>[a-z0-9-_:]+),(?P<x>-?\d+(\.\d+)?),(?P<y>-?\d+(\.\d+)?),(?P<zoom>-?\d+(\.\d+)?))?'
|
pos = r'(@(?P<level>[a-z0-9-_:]+),(?P<x>-?\d+(\.\d+)?),(?P<y>-?\d+(\.\d+)?),(?P<zoom>-?\d+(\.\d+)?))?'
|
||||||
embed = r'(?P<embed>embed/)?'
|
embed = r'(?P<embed>embed/)?'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^%s(?P<mode>[l])/%s/%s%s$' % (embed, slug, details, pos), map_index, name='site.index'),
|
url(r'^%s(?P<mode>[l])/%s/(%s|%s)%s$' % (embed, slug, details, nearby, pos), map_index, name='site.index'),
|
||||||
url(r'^%s(?P<mode>[od])/%s/%s$' % (embed, slug, pos), map_index, name='site.index'),
|
url(r'^%s(?P<mode>[od])/%s/%s$' % (embed, slug, pos), map_index, name='site.index'),
|
||||||
url(r'^%sr/%s/%s/(%s|%s)%s$' % (embed, slug, slug2, details, options, pos), map_index, name='site.index'),
|
url(r'^%sr/%s/%s/(%s|%s)%s$' % (embed, slug, slug2, details, options, pos), map_index, name='site.index'),
|
||||||
url(r'^%s(?P<mode>r)/%s$' % (embed, pos), map_index, name='site.index'),
|
url(r'^%s(?P<mode>r)/%s$' % (embed, pos), map_index, name='site.index'),
|
||||||
|
|
|
@ -57,7 +57,7 @@ def check_location(location: Optional[str], request) -> Optional[SpecificLocatio
|
||||||
return location
|
return location
|
||||||
|
|
||||||
|
|
||||||
def map_index(request, mode=None, slug=None, slug2=None, details=None, options=None,
|
def map_index(request, mode=None, slug=None, slug2=None, details=None, options=None, nearby=None,
|
||||||
level=None, x=None, y=None, zoom=None, embed=None):
|
level=None, x=None, y=None, zoom=None, embed=None):
|
||||||
|
|
||||||
# check for access token
|
# check for access token
|
||||||
|
@ -108,6 +108,7 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N
|
||||||
'sidebar': routing or destination is not None,
|
'sidebar': routing or destination is not None,
|
||||||
'details': True if details else False,
|
'details': True if details else False,
|
||||||
'options': True if options else False,
|
'options': True if options else False,
|
||||||
|
'nearby': True if nearby else False,
|
||||||
}
|
}
|
||||||
|
|
||||||
levels = levels_by_short_label_for_request(request)
|
levels = levels_by_short_label_for_request(request)
|
||||||
|
|
BIN
src/c3nav/static/img/marker-icon-nearby-2x.png
Normal file
BIN
src/c3nav/static/img/marker-icon-nearby-2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
src/c3nav/static/img/marker-icon-nearby.png
Normal file
BIN
src/c3nav/static/img/marker-icon-nearby.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Loading…
Add table
Add a link
Reference in a new issue