diff --git a/src/server/mod.rs b/src/server/mod.rs index f62039a..28c2682 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -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") } diff --git a/src/server/splitlist.rs b/src/server/splitlist.rs index 8e3760c..797f04c 100644 --- a/src/server/splitlist.rs +++ b/src/server/splitlist.rs @@ -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 { +) -> (Vec, Vec) { 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::>() - } else { - photos.iter().map(PhotoLink::from).collect::>() - } + ( + 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() + } else { + photos.iter().map(PhotoLink::from).collect() + }, + get_positions(&photos, c), + ) +} + +pub fn get_positions(photos: &[Photo], c: &PgConnection) -> Vec { + 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> { diff --git a/src/server/views_by_date.rs b/src/server/views_by_date.rs index 06b8ebc..5046c67 100644 --- a/src/server/views_by_date.rs +++ b/src/server/views_by_date.rs @@ -190,6 +190,7 @@ pub fn all_null_date<'mw>( .iter() .map(PhotoLink::from) .collect::>(), + &[], // 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, ) }) } diff --git a/templates/data_positions.rs.html b/templates/data_positions.rs.html new file mode 100644 index 0000000..699d73e --- /dev/null +++ b/templates/data_positions.rs.html @@ -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]}]"} diff --git a/templates/details.rs.html b/templates/details.rs.html index 81af9b6..e92a7a4 100644 --- a/templates/details.rs.html +++ b/templates/details.rs.html @@ -25,7 +25,6 @@ @if let Some(ref pos) = *position {

Position: @pos.x @pos.y

} @if let Some(ref a) = *attribution {

Av: @a

} @if let Some(ref c) = *camera{

Camera: @c.model (@c.manufacturer)

} - }) diff --git a/templates/index.rs.html b/templates/index.rs.html index 3574b6d..2dafdf4 100644 --- a/templates/index.rs.html +++ b/templates/index.rs.html @@ -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, { -
+
@for p in photos {@:photo_link(p)}
}) diff --git a/templates/person.rs.html b/templates/person.rs.html index 44fde78..bbd4889 100644 --- a/templates/person.rs.html +++ b/templates/person.rs.html @@ -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), &[], { -
+
@for p in photos {@:photo_link(p)}
}) diff --git a/templates/place.rs.html b/templates/place.rs.html index 578b3b7..86bacfc 100644 --- a/templates/place.rs.html +++ b/templates/place.rs.html @@ -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), &[], { -
+
@for p in photos {@:photo_link(p)}
}) diff --git a/templates/tag.rs.html b/templates/tag.rs.html index da99e38..42f6ac6 100644 --- a/templates/tag.rs.html +++ b/templates/tag.rs.html @@ -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), &[], { -
+
@for p in photos {@:photo_link(p)}
}) diff --git a/ux.js b/ux.js index 02b5c91..238ecb1 100644 --- a/ux.js +++ b/ux.js @@ -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', '
'); + 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: '© OpenStreetMap contributors' }).addTo(map); L.marker(pos).addTo(map); } - let h = d.querySelector('head'); - let m = d.querySelector('.meta'); - m.insertAdjacentHTML('beforeend', '
'); - 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: '© OpenStreetMap contributors' + }).addTo(map); + pos.forEach(p => L.marker(p).addTo(map)); + } + prepare_map(() => initmap(JSON.parse(poss))) } })(document)