Previous example: <--
web-sys: A requestAnimationFrame Loop
web-sys: A simple painting program.
A simple painting program.
_ wasm-bindgen Guide{target="_blank"}
web-sys: A simple painting program{target="_blank"}
This time we do everything from the Rust side.
setup the project
cargo new paint --lib
cd paint
mkdir -p www/js www/html
cargo add wasm-bindgen js-sys
- Edit Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
js-sys = "0.3.66"
wasm-bindgen = "0.2.89"
[dependencies.web-sys]
version = "0.3.66"
features = [
'CanvasRenderingContext2d',
'CssStyleDeclaration',
'Document',
'Element',
'EventTarget',
'HtmlCanvasElement',
'HtmlElement',
'MouseEvent',
'Node',
'Window',
]
The code
- index.html
<!doctype html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<title>Paint: nobundle</title>
</head>
<body>
<script type="module" src="../js/index.js"></script>
</body>
</html>
- index.js
import init from '../pkg/paint.js';
const run = async () => {
await init().catch(console.error);
};
/*
async function run() {
const wasm = await init().catch(console.error);
}
*/
run();
- Rust side
#![allow(unused)] fn main() { // src/lib.rs use std::cell::Cell; use std::rc::Rc; use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] fn start() -> Result<(), JsValue> { let document = web_sys::window().unwrap().document().unwrap(); let canvas = document .create_element("canvas")? .dyn_into::<web_sys::HtmlCanvasElement>()?; document.body().unwrap().append_child(&canvas)?; canvas.set_width(640); canvas.set_height(480); canvas.style().set_property("border", "solid")?; let context = canvas .get_context("2d")? .unwrap() .dyn_into::<web_sys::CanvasRenderingContext2d>()?; let context = Rc::new(context); let pressed = Rc::new(Cell::new(false)); { let context = context.clone(); let pressed = pressed.clone(); let closure = Closure::<dyn FnMut(_)>::new(move |event: web_sys::MouseEvent| { context.begin_path(); context.move_to(event.offset_x() as f64, event.offset_y() as f64); pressed.set(true); }); canvas.add_event_listener_with_callback("mousedown", closure.as_ref().unchecked_ref())?; closure.forget(); } { let context = context.clone(); let pressed = pressed.clone(); let closure = Closure::<dyn FnMut(_)>::new(move |event: web_sys::MouseEvent| { if pressed.get() { context.line_to(event.offset_x() as f64, event.offset_y() as f64); context.stroke(); context.begin_path(); context.move_to(event.offset_x() as f64, event.offset_y() as f64); } }); canvas.add_event_listener_with_callback("mousemove", closure.as_ref().unchecked_ref())?; closure.forget(); } { let closure = Closure::<dyn FnMut(_)>::new(move |event: web_sys::MouseEvent| { pressed.set(false); context.line_to(event.offset_x() as f64, event.offset_y() as f64); context.stroke(); }); canvas.add_event_listener_with_callback("mouseup", closure.as_ref().unchecked_ref())?; closure.forget(); } Ok(()) } }
build and serve
wasm-pack build --target web --no-typescript --out-dir www/pkg
http www
open index.html
firefox http://localhost:8000/html/
What's next?
Next example: web-sys: Wasm in Web Worker -->