From 1ed0f5f95b3c63e3efc24b65a1961bb4c7089223 Mon Sep 17 00:00:00 2001 From: Johannes Heuel Date: Tue, 23 Aug 2022 17:50:18 +0200 Subject: [PATCH] move layout code to layout --- .drone.yml | 9 +++ Cargo.lock | 124 ++++++++++++++++----------------- frontend/Cargo.toml | 2 +- frontend/src/gallery/grid.rs | 92 +----------------------- frontend/src/gallery/layout.rs | 90 ++++++++++++++++++++++++ frontend/src/gallery/mod.rs | 2 + frontend/src/main.rs | 44 ++++++++++-- 7 files changed, 205 insertions(+), 158 deletions(-) create mode 100644 .drone.yml create mode 100644 frontend/src/gallery/layout.rs diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..6ddf00a --- /dev/null +++ b/.drone.yml @@ -0,0 +1,9 @@ +kind: pipeline +type: docker +name: default + +steps: + - name: pre-commit + image: iamthefij/drone-pre-commit:latest + commands: + - pre-commit run --all-files diff --git a/Cargo.lock b/Cargo.lock index f57fdd8..f7da1a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,18 +304,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + [[package]] name = "arc-swap" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "askama_escape" version = "0.10.3" @@ -875,6 +875,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" dependencies = [ + "futures-channel", "gloo-events", "js-sys", "wasm-bindgen", @@ -932,6 +933,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" dependencies = [ + "futures-channel", + "futures-core", "js-sys", "wasm-bindgen", ] @@ -1115,19 +1118,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.126" @@ -1247,17 +1237,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -1533,6 +1512,12 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1599,6 +1584,18 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" +dependencies = [ + "fnv", + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.137" @@ -1688,12 +1685,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "subtle" version = "2.4.1" @@ -2116,14 +2107,15 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "ybc" version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c409d21870c31cc3beb3b5ba8447306ecfac198876fa73bdce861b23299121" +source = "git+https://github.com/jheuel/ybc?branch=yew-0-19-update#46e5c394b537d7fb9697b985b56945a15871928e" dependencies = [ "derive_more", + "serde", + "wasm-bindgen", "web-sys", - "yew 0.18.0", + "yew 0.19.3", + "yew-agent", "yew-router", - "yewtil", ] [[package]] @@ -2173,6 +2165,25 @@ dependencies = [ "yew-macro 0.19.3", ] +[[package]] +name = "yew-agent" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616700dc3851945658c44ba4477ede6b77c795462fbbb9b0ad9a8b6273a3ca77" +dependencies = [ + "anymap2", + "bincode", + "gloo-console", + "gloo-utils", + "js-sys", + "serde", + "slab", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew 0.19.3", +] + [[package]] name = "yew-hooks" version = "0.1.56" @@ -2218,44 +2229,33 @@ dependencies = [ [[package]] name = "yew-router" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27666236d9597eac9be560e841e415e20ba67020bc8cd081076be178e159c8bc" +checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2" dependencies = [ - "cfg-if 1.0.0", - "cfg-match", - "gloo 0.2.1", + "gloo 0.4.2", + "gloo-utils", "js-sys", - "log", - "nom", + "route-recognizer", "serde", - "serde_json", + "serde-wasm-bindgen", + "serde_urlencoded", + "thiserror", "wasm-bindgen", "web-sys", - "yew 0.18.0", + "yew 0.19.3", "yew-router-macro", - "yew-router-route-parser", ] [[package]] name = "yew-router-macro" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0ace2924b7a175e2d1c0e62ee7022a5ad840040dcd52414ce5f410ab322dba" +checksum = "39049d193b52eaad4ffc80916bf08806d142c90b5edcebd527644de438a7e19a" dependencies = [ "proc-macro2", "quote", "syn", - "yew-router-route-parser", -] - -[[package]] -name = "yew-router-route-parser" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de4a67208fb46b900af18a7397938b01f379dfc18da34799cfa8347eec715697" -dependencies = [ - "nom", ] [[package]] diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 6680546..4bf1f21 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -12,7 +12,7 @@ wasm-bindgen-futures = "0.4.32" gloo-net = "0.2.3" weblog = "0.3.0" wee_alloc = "0.4.5" -ybc = "0.2" +ybc = { git = "https://github.com/jheuel/ybc", branch = "yew-0-19-update" } yew = "0.19" yew-hooks = "0.1.56" pathfinding = "3.0.13" diff --git a/frontend/src/gallery/grid.rs b/frontend/src/gallery/grid.rs index cd74c29..b1902e4 100644 --- a/frontend/src/gallery/grid.rs +++ b/frontend/src/gallery/grid.rs @@ -6,6 +6,8 @@ use yew::prelude::*; use yew::{function_component, html}; +use super::layout::*; + #[derive(Clone, Debug, Properties, PartialEq)] pub struct GridProps { #[prop_or_default] @@ -14,95 +16,6 @@ pub struct GridProps { pub width: u32, } -fn get_common_height(row: &[OutputPicture], container_width: u32, margin: u32) -> f32 { - let row_width: u32 = container_width - row.len() as u32 * (margin * 2); - let total_aspect_ratio: f32 = row - .iter() - .map(|p| (p.width as f32) / (p.height as f32)) - .sum(); - row_width as f32 / total_aspect_ratio -} - -fn cost( - photos: &[OutputPicture], - i: usize, - j: usize, - width: u32, - target_height: u32, - margin: u32, -) -> u32 { - let common_height = get_common_height(&photos[i..j], width, margin); - (common_height - target_height as f32).powi(2) as u32 -} - -fn make_successors( - target_height: u32, - container_width: u32, - photos: &Vec, - limit_node_search: usize, - margin: u32, -) -> Vec> { - let mut results = vec![Vec::new(); photos.len()]; - (0..photos.len()).for_each(|start| { - for j in start + 1..photos.len() + 1 { - if j - start > limit_node_search { - break; - } - results[start].push(( - j, - cost(photos, start, j, container_width, target_height, margin), - )); - } - }); - results -} - -// guesstimate how many neighboring nodes should be searched based on -// the aspect ratio of the container with images having an avg AR of 1.5 -// as the minimum amount of photos per row, plus some nodes -fn find_ideal_node_search(target_row_height: u32, container_width: u32) -> usize { - let row_aspect_ratio = container_width as f32 / target_row_height as f32; - (row_aspect_ratio / 1.5) as usize + 8 -} - -fn compute_row_layout( - container_width: u32, - limit_node_search: usize, - target_height: u32, - margin: u32, - photos: &Vec, -) -> Option> { - console_log!("compute row layout for width: {}", container_width); - - if photos.is_empty() { - return None; - } - - let successors = make_successors( - target_height, - container_width, - photos, - limit_node_search, - margin, - ); - let path = dijkstra(&0, |p| successors[*p].clone(), |p| *p == photos.len()); - let (path, _cost) = if let Some(p) = path { - p - } else { - (Vec::new(), 0) - }; - let mut dimensions: Vec<(u32, u32)> = Vec::with_capacity(photos.len()); - for i in 1..path.len() { - let row = &photos[path[i - 1]..path[i]]; - let height = get_common_height(row, container_width, margin) as u32; - (path[i - 1]..path[i]).for_each(|j| { - let ratio = photos[j].width as f32 / photos[j].height as f32; - dimensions.push(((height as f32 * ratio) as u32, height)); - }); - } - Some(dimensions) -} - #[function_component(Grid)] pub fn grid(props: &GridProps) -> Html { let target_height = 300; @@ -127,7 +40,6 @@ pub fn grid(props: &GridProps) -> Html { "display: flex;", "flex-wrap: wrap;", "flex-direction: row;", - "border: 1px solid black;", )}> { props.pictures.iter().zip(dimensions).map(|(p, d)| html!{} diff --git a/frontend/src/gallery/layout.rs b/frontend/src/gallery/layout.rs new file mode 100644 index 0000000..9b22a3d --- /dev/null +++ b/frontend/src/gallery/layout.rs @@ -0,0 +1,90 @@ +use common::OutputPicture; +use pathfinding::prelude::dijkstra; +use weblog::console_log; + + +pub fn get_common_height(row: &[OutputPicture], container_width: u32, margin: u32) -> f32 { + let row_width: u32 = container_width - row.len() as u32 * (margin * 2); + let total_aspect_ratio: f32 = row + .iter() + .map(|p| (p.width as f32) / (p.height as f32)) + .sum(); + row_width as f32 / total_aspect_ratio +} + +pub fn cost( + photos: &[OutputPicture], + i: usize, + j: usize, + width: u32, + target_height: u32, + margin: u32, +) -> u32 { + let common_height = get_common_height(&photos[i..j], width, margin); + (common_height - target_height as f32).powi(2) as u32 +} + +pub fn make_successors( + target_height: u32, + container_width: u32, + photos: &Vec, + limit_node_search: usize, + margin: u32, +) -> Vec> { + let mut results = vec![Vec::new(); photos.len()]; + (0..photos.len()).for_each(|start| { + for j in start + 1..photos.len() + 1 { + if j - start > limit_node_search { + break; + } + results[start].push(( + j, + cost(photos, start, j, container_width, target_height, margin), + )); + } + }); + results +} + +pub fn find_ideal_node_search(target_row_height: u32, container_width: u32) -> usize { + let row_aspect_ratio = container_width as f32 / target_row_height as f32; + (row_aspect_ratio / 1.5) as usize + 8 +} + +pub fn compute_row_layout( + container_width: u32, + limit_node_search: usize, + target_height: u32, + margin: u32, + photos: &Vec, +) -> Option> { + console_log!("compute row layout for width: {}", container_width); + + if photos.is_empty() { + return None; + } + + let successors = make_successors( + target_height, + container_width, + photos, + limit_node_search, + margin, + ); + let path = dijkstra(&0, |p| successors[*p].clone(), |p| *p == photos.len()); + let (path, _cost) = if let Some(p) = path { + p + } else { + (Vec::new(), 0) + }; + let mut dimensions: Vec<(u32, u32)> = Vec::with_capacity(photos.len()); + for i in 1..path.len() { + let row = &photos[path[i - 1]..path[i]]; + let height = get_common_height(row, container_width, margin) as u32; + (path[i - 1]..path[i]).for_each(|j| { + let ratio = photos[j].width as f32 / photos[j].height as f32; + dimensions.push(((height as f32 * ratio) as u32, height)); + }); + } + Some(dimensions) +} diff --git a/frontend/src/gallery/mod.rs b/frontend/src/gallery/mod.rs index 9e8e28f..4c8eb77 100644 --- a/frontend/src/gallery/mod.rs +++ b/frontend/src/gallery/mod.rs @@ -1,3 +1,5 @@ +pub mod layout; + pub mod grid; pub use grid::Grid; diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 48a9d55..ba98610 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -11,6 +11,10 @@ use gloo_net::http::Request; use wasm_bindgen::prelude::*; use yew_hooks::prelude::*; +use ybc::NavbarFixed::Top; +use ybc::TileCtx::{Ancestor, Child, Parent}; +use ybc::TileSize::*; + use gallery::Grid; use yew::prelude::*; @@ -20,12 +24,11 @@ fn app() -> Html { let node = use_node_ref(); let size = use_size(node.clone()); - let pictures = use_state(|| vec![]); + let pictures = use_state(std::vec::Vec::new); { let pictures = pictures.clone(); use_effect_with_deps( move |_| { - let pictures = pictures.clone(); wasm_bindgen_futures::spawn_local(async move { let url = "/api/pictures/"; let fetched_pictures: Vec = Request::get(url) @@ -42,12 +45,43 @@ fn app() -> Html { (), ); } + let navbrand = html! { + + {"Photos"} + + }; + let navstart = html! {}; + let navend = html! { + <> + + + {"Photos"} + + + + }; html! { <> -
- -
+ + + + + +
+ +
+
+
+
+
} }