use std::rc::Rc; use std::sync::Mutex; use log::{Level, debug, info}; use wasm_bindgen::prelude::*; use render_loop::RenderLoop; use state::State; use web_sys::Event; mod line; mod point; mod render_loop; mod state; type JSResult = Result; type HandlerClosure = Closure JSResult<()>>; fn window() -> web_sys::Window { web_sys::window().expect("no window") } fn document() -> web_sys::Document { window().document().expect("no document") } fn canvas() -> JSResult { let x = document().query_selector("canvas")?.ok_or("no canvas")?; Ok(x.dyn_into::()?) } fn fps() -> JSResult { let x = document().query_selector("#fps")?.ok_or("no fps counter")?; Ok(x.dyn_into::()?) } fn go() -> JSResult { let x = document().query_selector("button")?.ok_or("no go button")?; Ok(x.dyn_into::()?) } #[wasm_bindgen(start)] pub fn init() -> JSResult<()> { console_log::init_with_level(Level::Debug) .map_err(|e| format!("couldn't init console: {e}"))?; info!("wasm init"); let paused = Rc::new(Mutex::new(true)); let p1 = paused.clone(); let mut s = State::new(canvas()?, fps()?)?; s.render_frame(0.0)?; let render_loop = RenderLoop::new(move |t| { s.render_frame(t)?; s.update()?; Ok(!*paused.lock().unwrap()) }); let a: HandlerClosure = Closure::new(move |e| { debug!("go clicked: {:?}", e); let mut p = p1.lock().unwrap(); *p = !*p; let text = if *p { "go" } else { render_loop.start()?; "pause" }; go()?.set_text_content(Some(text)); Ok(()) }); go()?.set_onclick(Some(a.as_ref().unchecked_ref())); // otherwise it gets dropped after we're done, invalidating the // handler. a.forget(); Ok(()) }