Trying to use `click` Event Closures in `web_sys`

⚓ rust    📅 2025-05-05    👤 surdeus    👁️ 8      

surdeus

Warning

This post was published 60 days ago. The information described in this article may have changed.

I have this struct:

#[wasm_bindgen]
pub struct App {
	animation_id: i32,
	game: Game,
	canvas: HtmlCanvasElement,
	context: CanvasRenderingContext2d,
	images: HashMap<ImageKey, HtmlImageElement>,
}

I'm trying to attach a closure as a click event listener to the canvas member. This closure needs to call mutable methods on the game member, but I'm not sure how to go about that.

Here's what I'm trying to do:

	fn attach_event_listeners(app: &App) {
		{
			let el = app.canvas.clone();

			let cb = Closure::<dyn FnMut(_)>::new(move |event: MouseEvent| {
				let rect = el.get_bounding_client_rect();
				let x = event.client_x() - rect.left() as i32;
				let y = event.client_y() - rect.top() as i32;
				let x_tile = (x / PIXELS_PER_CELL as i32) as i8;
				let y_tile = (y / PIXELS_PER_CELL as i32) as i8;

				let index = app.game.get_cell_index(x_tile, y_tile).unwrap(); /* PROBLEM */
				let cell = game.as_mut().unwrap().cells().get(index).unwrap(); /* PROBLEM */

				app.game.reveal_cell(x_tile, y_tile).unwrap(); /* PROBLEM */

				event.prevent_default();
			});

			app.canvas
				.add_event_listener_with_callback("click", cb.as_ref().unchecked_ref())
				.unwrap();

			cb.forget();
		}
	}

This obviously doesn't work because these closures use the move keyword to move ownership. I've been looking through the examples in the web_sys crate's repo, and it looks like I might need to wrap it in Rc and Cell smart pointers as an escape hatch to get around some of the borrowing rules in this case. Is this correct?

I get the feeling that I'm going about this wrong.

1 post - 1 participant

Read full topic

🏷️ rust_feed