From 97d2aaa9536305009ca8a1080dbd13115ece43f7 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sun, 4 Sep 2022 02:26:24 +1000 Subject: [PATCH] Add web_aspect_ratio example (#2209) * Add web_aspect_ratio example * Review feedback --- Cargo.toml | 1 + examples/web.rs | 6 +- examples/web_aspect_ratio.rs | 103 +++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 examples/web_aspect_ratio.rs diff --git a/Cargo.toml b/Cargo.toml index 22a237eb..6bd0ee78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,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.rs b/examples/web.rs index 71e5dfd6..82a3971a 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 00000000..0bbba211 --- /dev/null +++ b/examples/web_aspect_ratio.rs @@ -0,0 +1,103 @@ +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; + 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 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)] + 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!") + // 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(); + + 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(); + + // 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; 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)); + 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(); + } +}