diff --git a/Cargo.toml b/Cargo.toml index 537ab4a669..dcc7edf65c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,9 +149,14 @@ features = [ 'Node', 'PointerEvent', 'Window', - 'WheelEvent' + 'WheelEvent', ] +[target.'cfg(target_family = "wasm")'.dev-dependencies.web_sys] +package = "web-sys" +version = "0.3.22" +features = ['HtmlScriptElement'] + [target.'cfg(target_family = "wasm")'.dependencies] js-sys = "0.3" wasm-bindgen = "0.2.45" diff --git a/examples/wasm_custom_event.rs b/examples/wasm_custom_event.rs new file mode 100644 index 0000000000..389db76bc8 --- /dev/null +++ b/examples/wasm_custom_event.rs @@ -0,0 +1,123 @@ +/// This example will show how to call a Rust function from JavaScript +/// You should see the number 42 appear in browser console output when you click the button + +#[cfg(not(wasm_platform))] +pub fn main() { + panic!("This example is only meant to be compiled for wasm target") +} + +#[cfg(wasm_platform)] +pub fn main() { + panic!("Please run `cargo run-wasm --example wasm_custom_event`") +} + +#[cfg(wasm_platform)] +mod wasm { + use once_cell::unsync::OnceCell; + use wasm_bindgen::prelude::*; + use wasm_bindgen::JsCast; + use web_sys::HtmlScriptElement; + use winit::event::{Event, WindowEvent}; + use winit::event_loop::{EventLoop, EventLoopBuilder, EventLoopProxy}; + use winit::window::{Window, WindowBuilder}; + + + thread_local! { + pub static EVENT_LOOP_PROXY: OnceCell> = OnceCell::new(); + } + + // Function to be called from JS + fn wasm_call() -> u32 { + 42 + } + + #[derive(Debug, Clone, Copy)] + pub enum CustomEvent { + WasmCall, + } + + #[wasm_bindgen(start)] + pub fn run() { + console_log::init_with_level(log::Level::Debug).expect("error initializing logger"); + + let event_loop: EventLoop = + EventLoopBuilder::::with_user_event().build(); + + let event_loop_proxy = event_loop.create_proxy(); + + // Initialize the thread_local EVENT_LOOP_PROXY value + EVENT_LOOP_PROXY.with(|cell| { + cell.set(event_loop_proxy).unwrap(); + }); + + let window = WindowBuilder::new().build(&event_loop).unwrap(); + + insert_canvas(&window); + + event_loop.run(move |event, _, control_flow| { + control_flow.set_wait(); + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => control_flow.set_exit(), + Event::MainEventsCleared => { + window.request_redraw(); + } + // Handle custom events here + Event::UserEvent(CustomEvent::WasmCall) => { + // Send the result back to JS as proof that the custom event was handled + log::info!("{:?}", wasm_call()); + } + _ => (), + } + }); + } + + #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = "handleWasmCall"))] + pub fn handle_wasm_call() { + EVENT_LOOP_PROXY.with(|cell| { + cell.get().unwrap().send_event(CustomEvent::WasmCall).ok(); + }); + } + + pub fn insert_canvas(window: &Window) { + use winit::platform::web::WindowExtWebSys; + + let canvas = window.canvas(); + + let window = web_sys::window().unwrap(); + let document = window.document().unwrap(); + let body = document.body().unwrap(); + + // Set a background color for the canvas to make it easier to tell where the canvas is for debugging purposes. + canvas.style().set_property("background-color", "crimson").unwrap(); + body.append_child(&canvas).unwrap(); + + // Create script element + let script: HtmlScriptElement = document + .create_element("script") + .unwrap() + .dyn_into() + .unwrap(); + script.set_type("module"); + + // Your JavaScript code here, including creating the button and attaching the event handler + script.set_inner_text( + r#" + import { handleWasmCall } from "./wasm_custom_event.js"; + let button = document.createElement("button"); + button.innerHTML = "Favourite Number?"; + button.onclick = handleWasmCall; + document.body.appendChild(button); + "#, + ); + + let first_child = body.first_child(); + match first_child { + Some(node) => body.insert_before(&script, Some(&node)).unwrap(), + None => body.append_child(&script).unwrap(), + }; + } +} diff --git a/run-wasm/src/main.rs b/run-wasm/src/main.rs index 6961358d9b..909403e803 100644 --- a/run-wasm/src/main.rs +++ b/run-wasm/src/main.rs @@ -1,3 +1,13 @@ fn main() { - cargo_run_wasm::run_wasm_with_css("body { margin: 0px; }"); + cargo_run_wasm::run_wasm_with_css( + r#" + body { + margin: 0px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + "#, + ); }