Add maps to image lists.

This commit is contained in:
Rasmus Kaj 2018-02-07 20:56:23 +01:00
parent 24a7a34025
commit 28032e4026
10 changed files with 90 additions and 49 deletions

View File

@ -373,8 +373,8 @@ fn tag_one<'mw>(
let photos = Photo::query(req.authorized_user().is_some()).filter(
id.eq_any(photo_tags.select(photo_id).filter(tag_id.eq(tag.id))),
);
let links = links_by_time(req, photos);
return res.ok(|o| templates::tag(o, req, &links, &tag));
let (links, coords) = links_by_time(req, photos);
return res.ok(|o| templates::tag(o, req, &links, &coords, &tag));
}
res.not_found("Not a tag")
}
@ -432,8 +432,8 @@ fn place_one<'mw>(
Photo::query(req.authorized_user().is_some()).filter(id.eq_any(
photo_places.select(photo_id).filter(place_id.eq(place.id)),
));
let links = links_by_time(req, photos);
return res.ok(|o| templates::place(o, req, &links, &place));
let (links, coord) = links_by_time(req, photos);
return res.ok(|o| templates::place(o, req, &links, &coord, &place));
}
res.not_found("Not a place")
}
@ -485,8 +485,8 @@ fn person_one<'mw>(
.filter(person_id.eq(person.id)),
),
);
let links = links_by_time(req, photos);
return res.ok(|o| templates::person(o, req, &links, &person));
let (links, coords) = links_by_time(req, photos);
return res.ok(|o| templates::person(o, req, &links, &coords, &person));
}
res.not_found("Not a person")
}

View File

@ -2,7 +2,7 @@ use super::PhotoLink;
use super::views_by_date::query_date;
use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use models::Photo;
use models::{Coord, Photo};
use nickel::Request;
use nickel_diesel::DieselRequestExtensions;
use schema::photos;
@ -10,7 +10,7 @@ use schema::photos;
pub fn links_by_time<'a>(
req: &mut Request,
photos: photos::BoxedQuery<'a, Pg>,
) -> Vec<PhotoLink> {
) -> (Vec<PhotoLink>, Vec<Coord>) {
let c: &PgConnection = &req.db_conn();
use schema::photos::dsl::date;
let photos = if let Some(from_date) = query_date(req, "from") {
@ -24,15 +24,33 @@ pub fn links_by_time<'a>(
photos
};
let photos = photos.order(date.desc().nulls_last()).load(c).unwrap();
(
if let Some(groups) = split_to_groups(&photos) {
let path = req.path_without_query().unwrap_or("/");
groups
.iter()
.map(|g| PhotoLink::for_group(g, path))
.collect::<Vec<_>>()
.collect()
} else {
photos.iter().map(PhotoLink::from).collect::<Vec<_>>()
photos.iter().map(PhotoLink::from).collect()
},
get_positions(&photos, c),
)
}
pub fn get_positions(photos: &[Photo], c: &PgConnection) -> Vec<Coord> {
use schema::positions::dsl::*;
positions
.filter(photo_id.eq_any(photos.iter().map(|p| p.id)))
.select((latitude, longitude))
.load(c)
.unwrap_or_default() // TODO Log if there is a problem?
.into_iter()
.map(|(lat, long): (i32, i32)| Coord {
x: f64::from(lat) / 1e6,
y: f64::from(long) / 1e6,
})
.collect()
}
pub fn split_to_groups(photos: &[Photo]) -> Option<Vec<&[Photo]>> {

View File

@ -190,6 +190,7 @@ pub fn all_null_date<'mw>(
.iter()
.map(PhotoLink::from)
.collect::<Vec<_>>(),
&[], // TODO: positions.
)
})
}
@ -207,7 +208,7 @@ pub fn all_for_day<'mw>(
let photos = Photo::query(req.authorized_user().is_some())
.filter(date.ge(thedate))
.filter(date.lt(thedate + ChDuration::days(1)));
let links = links_by_time(req, photos);
let (links, coords) = links_by_time(req, photos);
if links.is_empty() {
res.not_found("No such image")
@ -219,6 +220,7 @@ pub fn all_for_day<'mw>(
&format!("Photos from {} {} {}", day, monthname(month), year),
&[Link::year(year), Link::month(year, month)],
&links,
&coords,
)
})
}

View File

@ -0,0 +1,5 @@
@use models::Coord;
@(coords: &[Coord])
@if let Some((c, rest)) = coords.split_first()
{ data-positions="[[@c.x,@c.y]@for c in rest {,[@c.x,@c.y]}]"}

View File

@ -25,7 +25,6 @@
@if let Some(ref pos) = *position {<p>Position: @pos.x @pos.y</p>}
@if let Some(ref a) = *attribution {<p>Av: @a</p>}
@if let Some(ref c) = *camera{<p>Camera: @c.model (@c.manufacturer)</p>}
</div>
</div>
})

View File

@ -1,12 +1,13 @@
@use ::Link;
@use models::Coord;
@use nickel::Request;
@use server::PhotoLink;
@use templates::{page_base, photo_link};
@use templates::{data_positions, page_base, photo_link};
@(req: &Request, title: &str, lpath: &[Link], photos: &[PhotoLink])
@(req: &Request, title: &str, lpath: &[Link], photos: &[PhotoLink], coords: &[Coord])
@:page_base(req, title, lpath, {
<div class="group">
<div class="group"@:data_positions(coords)>
@for p in photos {@:photo_link(p)}
</div>
})

View File

@ -1,11 +1,11 @@
@use nickel::Request;
@use models::Person;
@use models::{Coord, Person};
@use server::PhotoLink;
@use templates::{page_base, photo_link};
@use templates::{data_positions, page_base, photo_link};
@(req: &Request, photos: &[PhotoLink], person: &Person)
@(req: &Request, photos: &[PhotoLink], coords: &[Coord], person: &Person)
@:page_base(req, &format!("Photos with {}", person.person_name), &[], {
<div class="group">
<div class="group"@:data_positions(coords)>
@for p in photos {@:photo_link(p)}
</div>
})

View File

@ -1,11 +1,11 @@
@use nickel::Request;
@use models::{Place};
@use models::{Coord, Place};
@use server::PhotoLink;
@use templates::{page_base, photo_link};
@use templates::{data_positions, page_base, photo_link};
@(req: &Request, photos: &[PhotoLink], place: &Place)
@(req: &Request, photos: &[PhotoLink], coords: &[Coord], place: &Place)
@:page_base(req, &format!("Photos from {}", place.place_name), &[], {
<div class="group">
<div class="group"@:data_positions(coords)>
@for p in photos {@:photo_link(p)}
</div>
})

View File

@ -1,12 +1,12 @@
@use nickel::Request;
@use models::Tag;
@use models::{Coord, Tag};
@use server::PhotoLink;
@use templates::{page_base, photo_link};
@use templates::{data_positions, page_base, photo_link};
@(req: &Request, photos: &[PhotoLink], tag: &Tag)
@(req: &Request, photos: &[PhotoLink], coords: &[Coord], tag: &Tag)
@:page_base(req, &format!("Photos tagged {}", tag.tag_name), &[], {
<div class="group">
<div class="group"@:data_positions(coords)>
@for p in photos {@:photo_link(p)}
</div>
})

46
ux.js
View File

@ -19,30 +19,46 @@
if (i) {
i.addEventListener('click', e => { i.classList.toggle('zoom') });
}
function prepare_map(cb) {
let h = d.querySelector('head');
let m = d.querySelector('.meta') || d.querySelector('main');
m.insertAdjacentHTML('beforeend', '<div id="map"></div>');
var map = d.getElementById('map');
map.style.height = 3 * map.clientWidth / 4 + "px";
var slink = d.createElement('script');
slink.type = 'text/javascript';
slink.src = 'https://rasmus.krats.se/static/leaflet077c/leaflet.js';
slink.async = 'async';
slink.onload = cb;
h.append(slink);
var csslink = d.createElement('link');
csslink.rel = 'stylesheet';
csslink.href = 'https://rasmus.krats.se/static/leaflet077c/leaflet.css';
h.append(csslink);
}
let details = d.querySelector('.details');
let pos = details && details.dataset.position
if (pos) {
function initmap(pos) {
var map = document.getElementById('map');
map.style.height = 3 * map.clientWidth / 4 + "px";
var map = L.map('map').setView(pos, 16);
L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
L.marker(pos).addTo(map);
}
let h = d.querySelector('head');
let m = d.querySelector('.meta');
m.insertAdjacentHTML('beforeend', '<div id="map"></div>');
var slink = document.createElement('script');
slink.type = 'text/javascript';
slink.src = 'https://rasmus.krats.se/static/leaflet077c/leaflet.js';
slink.async = 'async';
slink.onload = () => initmap(JSON.parse(pos));
h.append(slink);
var csslink = document.createElement('link');
csslink.rel = 'stylesheet';
csslink.href = 'https://rasmus.krats.se/static/leaflet077c/leaflet.css';
h.append(csslink);
prepare_map(() => initmap(JSON.parse(pos)))
}
let group = d.querySelector('.group');
let poss = (details && details.dataset.positions) || (group && group.dataset.positions);
if (poss) {
function initmap(pos) {
var map = L.map('map');
map.fitBounds(L.polyline(pos).getBounds())
L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
pos.forEach(p => L.marker(p).addTo(map));
}
prepare_map(() => initmap(JSON.parse(poss)))
}
})(document)