From ac6ddfec5d207d0e5e814e866689c3db4a034aec Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sat, 26 Feb 2022 10:50:45 +1100 Subject: [PATCH 1/2] Add web_aspect_ratio example --- Cargo.toml | 1 + examples/web.rs | 6 +- examples/web_aspect_ratio.rs | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 examples/web_aspect_ratio.rs diff --git a/Cargo.toml b/Cargo.toml index 22a237eb81..093459be62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ mint = { version = "0.5.6", optional = true } [dev-dependencies] image = { version = "0.24.0", default-features = false, features = ["png"] } simple_logger = { version = "2.1.0", default_features = false } +web-sys = { version = "0.3.4", features = ['CanvasRenderingContext2d'] } [target.'cfg(target_os = "android")'.dependencies] # Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995 diff --git a/examples/web.rs b/examples/web.rs index 71e5dfd60a..82a3971a6e 100644 --- a/examples/web.rs +++ b/examples/web.rs @@ -15,7 +15,7 @@ pub fn main() { .unwrap(); #[cfg(target_arch = "wasm32")] - let log_list = wasm::create_log_list(&window); + let log_list = wasm::insert_canvas_and_create_log_list(&window); event_loop.run(move |event, _, control_flow| { control_flow.set_wait(); @@ -49,7 +49,7 @@ mod wasm { super::main(); } - pub fn create_log_list(window: &Window) -> web_sys::Element { + pub fn insert_canvas_and_create_log_list(window: &Window) -> web_sys::Element { use winit::platform::web::WindowExtWebSys; let canvas = window.canvas(); @@ -58,7 +58,7 @@ mod wasm { let document = window.document().unwrap(); let body = document.body().unwrap(); - // Set a background color for the canvas to make it easier to tell the where the canvas is for debugging purposes. + // Set a background color for the canvas to make it easier to tell where the canvas is for debugging purposes. canvas.style().set_css_text("background-color: crimson;"); body.append_child(&canvas).unwrap(); diff --git a/examples/web_aspect_ratio.rs b/examples/web_aspect_ratio.rs new file mode 100644 index 0000000000..d020d7c2ae --- /dev/null +++ b/examples/web_aspect_ratio.rs @@ -0,0 +1,107 @@ +pub fn main() { + println!("This example must be run with cargo run-wasm --example web_aspect_ratio") +} + +#[cfg(target_arch = "wasm32")] +mod wasm { + use wasm_bindgen::prelude::*; + use wasm_bindgen::JsCast; + use web_sys::{HtmlCanvasElement, HtmlElement}; + use winit::{ + dpi::PhysicalSize, + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::{Window, WindowBuilder}, + }; + + const EXPLANATION: &str = " +This example draws a circle in the middle of a 4/1 aspect ratio canvas which acts as a useful demonstration of winit's resize handling on web. +Even when the browser window is resized or aspect-ratio of the div changed the circle should always: +* Fill the entire width or height of the canvas (whichever is smaller) without exceeding it. +* Be perfectly round +* Not be blurry or pixelated (there is no antialiasing so you may still see jagged edges depending on the DPI of your monitor) +"; + + #[wasm_bindgen(start)] + pub fn run() { + console_log::init_with_level(log::Level::Debug).expect("error initializing logger"); + let event_loop = EventLoop::new(); + + let window = WindowBuilder::new() + .with_title("A fantastic window!") + // A small default size is used to better demonstrate issues that come from failing to update the size + .with_inner_size(PhysicalSize::new(100, 100)) + .build(&event_loop) + .unwrap(); + + let canvas = create_canvas(&window); + + // Render once with the size info we currently have + render_circle(&canvas, window.inner_size()); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::Resized(resize), + window_id, + } if window_id == window.id() => { + render_circle(&canvas, resize); + } + _ => (), + } + }); + } + + pub fn create_canvas(window: &Window) -> HtmlCanvasElement { + use winit::platform::web::WindowExtWebSys; + + let web_window = web_sys::window().unwrap(); + let document = web_window.document().unwrap(); + let body = document.body().unwrap(); + + let parent_div = document.create_element("div").unwrap(); + parent_div + .dyn_ref::() + .unwrap() + .style() + .set_css_text("margin: auto; width: 50%; aspect-ratio: 4 / 1;"); + body.append_child(&parent_div).unwrap(); + + // Set a background color for the canvas to make it easier to tell the where the canvas is for debugging purposes. + let canvas = window.canvas(); + canvas + .style() + .set_css_text("display: block; width: 100%; height: 100%; background-color: crimson;"); + parent_div.append_child(&canvas).unwrap(); + + let explanation = document.create_element("pre").unwrap(); + explanation.set_text_content(Some(EXPLANATION)); + body.append_child(&explanation).unwrap(); + + canvas + } + + pub fn render_circle(canvas: &HtmlCanvasElement, size: PhysicalSize) { + log::info!("rendering circle with canvas size: {:?}", size); + let context = canvas + .get_context("2d") + .unwrap() + .unwrap() + .dyn_into::() + .unwrap(); + + context.begin_path(); + context + .arc( + size.width as f64 / 2.0, + size.height as f64 / 2.0, + size.width.min(size.height) as f64 / 2.0, + 0.0, + std::f64::consts::PI * 2.0, + ) + .unwrap(); + context.fill(); + } +} From bc2943f5efc9e5229c2d0af8d0ca586e127c9652 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sun, 27 Feb 2022 16:58:40 +1100 Subject: [PATCH 2/2] Review feedback --- Cargo.toml | 2 +- examples/web_aspect_ratio.rs | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 093459be62..6bd0ee780d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,6 @@ mint = { version = "0.5.6", optional = true } [dev-dependencies] image = { version = "0.24.0", default-features = false, features = ["png"] } simple_logger = { version = "2.1.0", default_features = false } -web-sys = { version = "0.3.4", features = ['CanvasRenderingContext2d'] } [target.'cfg(target_os = "android")'.dependencies] # Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995 @@ -143,6 +142,7 @@ version = "0.2.45" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] console_log = "0.2" +web-sys = { version = "0.3.22", features = ['CanvasRenderingContext2d'] } [workspace] members = [ diff --git a/examples/web_aspect_ratio.rs b/examples/web_aspect_ratio.rs index d020d7c2ae..0bbba211db 100644 --- a/examples/web_aspect_ratio.rs +++ b/examples/web_aspect_ratio.rs @@ -6,7 +6,7 @@ pub fn main() { mod wasm { use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; - use web_sys::{HtmlCanvasElement, HtmlElement}; + use web_sys::HtmlCanvasElement; use winit::{ dpi::PhysicalSize, event::{Event, WindowEvent}, @@ -16,10 +16,13 @@ mod wasm { const EXPLANATION: &str = " This example draws a circle in the middle of a 4/1 aspect ratio canvas which acts as a useful demonstration of winit's resize handling on web. -Even when the browser window is resized or aspect-ratio of the div changed the circle should always: +Even when the browser window is resized or aspect-ratio of the canvas changed the circle should always: * Fill the entire width or height of the canvas (whichever is smaller) without exceeding it. * Be perfectly round * Not be blurry or pixelated (there is no antialiasing so you may still see jagged edges depending on the DPI of your monitor) + +Currently winit does not handle resizes on web so the circle is rendered incorrectly. +This example demonstrates the desired future functionality which will possibly be provided by https://github.com/rust-windowing/winit/pull/2074 "; #[wasm_bindgen(start)] @@ -29,7 +32,8 @@ Even when the browser window is resized or aspect-ratio of the div changed the c let window = WindowBuilder::new() .with_title("A fantastic window!") - // A small default size is used to better demonstrate issues that come from failing to update the size + // When running in a non-wasm environment this would set the window size to 100x100. + // However in this example it just sets a default initial size of 100x100 that is immediately overwritten due to the layout + styling of the page. .with_inner_size(PhysicalSize::new(100, 100)) .build(&event_loop) .unwrap(); @@ -61,20 +65,12 @@ Even when the browser window is resized or aspect-ratio of the div changed the c let document = web_window.document().unwrap(); let body = document.body().unwrap(); - let parent_div = document.create_element("div").unwrap(); - parent_div - .dyn_ref::() - .unwrap() - .style() - .set_css_text("margin: auto; width: 50%; aspect-ratio: 4 / 1;"); - body.append_child(&parent_div).unwrap(); - // Set a background color for the canvas to make it easier to tell the where the canvas is for debugging purposes. let canvas = window.canvas(); canvas .style() - .set_css_text("display: block; width: 100%; height: 100%; background-color: crimson;"); - parent_div.append_child(&canvas).unwrap(); + .set_css_text("display: block; background-color: crimson; margin: auto; width: 50%; aspect-ratio: 4 / 1;"); + body.append_child(&canvas).unwrap(); let explanation = document.create_element("pre").unwrap(); explanation.set_text_content(Some(EXPLANATION));