From 623c47147604f998cd2310c3892ef5b859a9a1a9 Mon Sep 17 00:00:00 2001 From: Calli Evers Date: Mon, 27 May 2024 21:34:09 +0200 Subject: [PATCH] feat: responsive canvas and grid on canvas --- Cargo.toml | 2 ++ index.html | 2 +- src/algorithm/grid.rs | 40 ++++++++++++++++++++++ src/algorithm/mod.rs | 17 ++++++++++ src/components/canvas.rs | 70 +++++++++++++++++++++++++++++++++++++-- src/components/navbar.rs | 2 +- src/components/sidebar.rs | 2 +- src/main.rs | 5 +-- 8 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 src/algorithm/grid.rs create mode 100644 src/algorithm/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 81787e5..2d5052f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,5 @@ edition = "2021" [dependencies] leptos = { version = "0.6.11", features = ["csr", "nightly"] } +web-sys = { version = "0.3", features = ["HtmlCanvasElement", "CanvasRenderingContext2d", "CssStyleDeclaration", "Element", "Window"] } +wasm-bindgen = { version = "0.2" } diff --git a/index.html b/index.html index 55a7330..cf6f25a 100644 --- a/index.html +++ b/index.html @@ -8,5 +8,5 @@ Algorithmically-Assisted Metro Map Design - + diff --git a/src/algorithm/grid.rs b/src/algorithm/grid.rs new file mode 100644 index 0000000..d83eed9 --- /dev/null +++ b/src/algorithm/grid.rs @@ -0,0 +1,40 @@ +use wasm_bindgen::JsValue; +use web_sys::CanvasRenderingContext2d; + +pub fn draw_grid(canvas: &CanvasRenderingContext2d, size: (u32, u32), square_size: u32) { + canvas.set_line_width(1.0); + canvas.set_stroke_style(&JsValue::from_str("grey")); + + draw_vertical_lines(canvas, size.0, square_size, size.1 / square_size); + draw_horizontal_lines(canvas, size.1, square_size, size.0 / square_size); +} + +fn draw_vertical_lines( + canvas: &CanvasRenderingContext2d, + length: u32, + square_size: u32, + count: u32, +) { + for i in 0..count { + let x = (i * square_size + square_size) as f64; + canvas.begin_path(); + canvas.move_to(x, 0.0); + canvas.line_to(x, length as f64); + canvas.stroke(); + } +} + +fn draw_horizontal_lines( + canvas: &CanvasRenderingContext2d, + length: u32, + square_size: u32, + count: u32, +) { + for i in 0..count { + let y = (i * square_size + square_size) as f64; + canvas.begin_path(); + canvas.move_to(0.0, y); + canvas.line_to(length as f64, y); + canvas.stroke(); + } +} diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs new file mode 100644 index 0000000..6d25b41 --- /dev/null +++ b/src/algorithm/mod.rs @@ -0,0 +1,17 @@ +use wasm_bindgen::JsCast; +use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; + +mod grid; + +use grid::draw_grid; + +pub fn redraw_canvas(canvas: &HtmlCanvasElement, size: (u32, u32)) { + let context = canvas + .get_context("2d") + .unwrap() + .unwrap() + .dyn_into::() + .unwrap(); + + draw_grid(&context, size, 30); +} diff --git a/src/components/canvas.rs b/src/components/canvas.rs index d91a14f..fdcec1b 100644 --- a/src/components/canvas.rs +++ b/src/components/canvas.rs @@ -1,10 +1,76 @@ +use leptos::html::Canvas; +use leptos::logging::log; use leptos::*; +use wasm_bindgen::closure::Closure; +use wasm_bindgen::JsCast; + +use crate::algorithm::redraw_canvas; + +fn redraw(canvas_node: &HtmlElement) { + // To have a canvas resize dynamically, we need to manually adjust its size + // CSS will NOT work, as it will just make everything blurry + let doc = window().document().expect("should have document"); + let win_height = window().inner_height().unwrap().as_f64().unwrap(); + let win_width = window().inner_width().unwrap().as_f64().unwrap(); + + // the navbar borders the top, so the height is `window - navbar` + let nav = doc + .get_element_by_id("navbar") + .expect("navbar should exist"); + let nav_height_px = window() + .get_computed_style(&nav) + .unwrap() + .expect("should have style") + .get_property_value("height") + .expect("should have height property"); + + let height = (win_height + - nav_height_px + .trim_end_matches("px") + .parse::() + .expect("height should be an integer")) as u32; + canvas_node.set_height(height); + + // the sidebar borders its side, so width is `window - sidebar` + let side = doc + .get_element_by_id("sidebar") + .expect("sidebar should exist"); + let side_width_px = window() + .get_computed_style(&side) + .unwrap() + .expect("should have style") + .get_property_value("width") + .expect("should have width property"); + + let width = (win_width + - side_width_px + .trim_end_matches("px") + .parse::() + .expect("width should be an integer")) as u32; + canvas_node.set_width(width); + + // Now the canvas is the correct size, we can draw it + log!("redrawing canvas"); + redraw_canvas(&*canvas_node, (height, width)); +} #[component] pub fn Canvas() -> impl IntoView { + let canvas_ref = create_node_ref::(); + + create_effect(move |_| { + let canvas_node = canvas_ref.get().expect("should be loaded now"); + + redraw(&canvas_node); + + let f = Closure::::new(move || redraw(&canvas_node)); + window().set_onresize(Some(f.as_ref().unchecked_ref())); + f.forget(); + }); + view! { -
- +
+
} } diff --git a/src/components/navbar.rs b/src/components/navbar.rs index e26f8fc..3ff8b4e 100644 --- a/src/components/navbar.rs +++ b/src/components/navbar.rs @@ -3,7 +3,7 @@ use leptos::*; #[component] pub fn Navbar() -> impl IntoView { view! { -