From fdc957cae7f5efca792b40df7ff90ec4f512269b Mon Sep 17 00:00:00 2001 From: brian cully Date: Sat, 27 Dec 2025 16:53:11 -0500 Subject: get wasm go button working --- src/lib.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/state.rs | 31 ++++--------------------- 2 files changed, 71 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f43b2ad..1c5f028 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ use std::cell::RefCell; +use std::sync::{Mutex}; use std::rc::Rc; -use log::{Level, info}; +use log::{Level, info, debug}; use wasm_bindgen::prelude::*; use state::State; @@ -28,12 +29,40 @@ fn window() -> web_sys::Window { web_sys::window().expect("no window") } +fn document() -> web_sys::Document { + window().document().expect("no document") +} + +fn canvas() -> Result { + let x = document() + .query_selector("canvas")? + .expect("canvas element"); + Ok(x.dyn_into::()?) +} + +fn fps() -> Result { + let x = document() + .query_selector("#fps")? + .expect("fps counter exists"); + Ok(x.dyn_into::()?) +} + +fn go() -> Result { + let x = document() + .query_selector("button")? + .expect("go button exists"); + Ok(x.dyn_into::()?) +} + #[wasm_bindgen(start)] pub fn init() -> Result<(), JsValue> { console_log::init_with_level(Level::Debug).expect("couldn't init console log"); info!("wasm init"); - let mut s = State::new()?; + let paused = Rc::new(Mutex::new(true)); + let p1 = paused.clone(); + + let mut s = State::new(canvas()?, fps()?)?; s.render_frame(0.0)?; // @@ -43,12 +72,13 @@ pub fn init() -> Result<(), JsValue> { let render_loop: Rc> = Rc::new(RefCell::new(RenderLoop::new())); { let closure: Closure = { - let render_loop = render_loop.clone(); + let render_loop_clone = render_loop.clone(); Closure::wrap(Box::new(move |t| { s.render_frame(t).expect("should render frame"); - if !s.paused { - let mut render_loop = render_loop.borrow_mut(); - render_loop.animation_id = if let Some(ref closure) = render_loop.closure { + let p = paused.lock().unwrap(); + if !*p { + let mut render_loop_mut = render_loop_clone.borrow_mut(); + render_loop_mut.animation_id = if let Some(ref closure) = render_loop_mut.closure { Some( window() .request_animation_frame(closure.as_ref().unchecked_ref()) @@ -60,18 +90,46 @@ pub fn init() -> Result<(), JsValue> { } })) }; - let mut render_loop = render_loop.borrow_mut(); - render_loop.animation_id = Some( + + let mut render_loop_last = render_loop.borrow_mut(); + render_loop_last.animation_id = Some( window() .request_animation_frame(closure.as_ref().unchecked_ref()) .expect("req anim frame"), ); - render_loop.closure = Some(closure); + render_loop_last.closure = Some(closure); } // // // + let a = Closure::::new(move || { + let mut p = p1.lock().unwrap(); + debug!("go clicked: {}", *p); + *p = !*p; + let text = if *p { + "go" + } else { + let render_loop_clone = render_loop.clone(); + let mut render_loop_mut = render_loop_clone.borrow_mut(); + render_loop_mut.animation_id = if let Some(ref closure) = render_loop_mut.closure { + Some( + window() + .request_animation_frame(closure.as_ref().unchecked_ref()) + .expect("req anim frame"), + ) + } else { + None + }; + "pause" + }; + go().expect("go button works").set_text_content(Some(text)); + }); + go()?.set_onclick(Some(a.as_ref().unchecked_ref())); + // otherwise it gets dropped after we're done, invalidating the + // handler. + a.forget(); + Ok(()) } diff --git a/src/state.rs b/src/state.rs index 4adb952..f5435f5 100644 --- a/src/state.rs +++ b/src/state.rs @@ -10,49 +10,27 @@ use crate::point::Point; pub const TAU: f64 = PI * 2.0; pub const MAX_SPEED: f64 = 0.01; -const NUM_POINTS: usize = 40; +const NUM_POINTS: usize = 10; const VELVEC_SCALE: f64 = 3.0; -fn window() -> web_sys::Window { - web_sys::window().expect("no window") -} - -fn document() -> web_sys::Document { - window().document().expect("no document") -} - -fn canvas() -> Result { - let x = document() - .query_selector("canvas")? - .expect("canvas element"); - Ok(x.dyn_into::()?) -} - #[derive(Debug)] pub struct State { canvas: HtmlCanvasElement, ctx: CanvasRenderingContext2d, fps: HtmlElement, points: Vec, - pub paused: bool, last_time: Option, inter_count: u16, } impl State { - pub fn new() -> Result { + pub fn new(canvas: HtmlCanvasElement, fps: HtmlElement) -> Result { debug!("State::new()"); - let canvas = canvas()?; let ctx: CanvasRenderingContext2d = canvas .get_context("2d")? .expect("2d context on canvas") .dyn_into()?; ctx.scale(canvas.width().into(), canvas.height().into())?; - let fps = document() - .query_selector("#fps")? - .expect("fps counter exists") - .dyn_into::() - .expect("is html element"); let points = (0..NUM_POINTS) .map(|_| Point::new(fastrand::f64(), fastrand::f64())) @@ -63,8 +41,7 @@ impl State { ctx, fps, points, - paused: false, - last_time: document().timeline().current_time(), + last_time: None, inter_count: 1, }) } @@ -75,12 +52,12 @@ impl State { let ic: f64 = self.inter_count.into(); let val: f64 = (1_000.0 * ic / (t - last_time)).trunc(); self.fps.set_text_content(Some(val.to_string().as_str())); - self.last_time = Some(t); self.inter_count = 1; } else { self.inter_count += 1; } } + self.last_time = Some(t); self.ctx.clear_rect( 0.0, -- cgit v1.3