1. はじめに
前回、Rust から WebAssembly を使う方法を書いたので、今回はその続きとして、Rust と WebAssembly を使って Canvas に描画してみます。
Canvas は、HTML5 で追加された描画用の要素で、JavaScript を使って描画することができます。
wasm-bindgen を使うことで、Rust から JavaScript の関数を呼び出すことができるので、Rust から Canvas に描画することができるようです。
wasm-pack は内部的に wasm-bindgen を使っているので、wasm-pack を使うことで wasm-bindgen の機能を使うことができます。
wasm-pack を使うことで開発ワークフローを効率化することができるようですが、npm で動かすためせっかく Docker で動くようにしたので、wasm-pack は使わず、wasm-bindgen で試してみます。
2. Cargo.toml の編集
[dependencies]
js-sys = "0.3.77"
wasm-bindgen = "0.2.100"
web-sys = { version = "0.3.77", features = ['CanvasRenderingContext2d', 'Document', 'Element', 'HtmlCanvasElement', 'Window'] }
3つのクレートを使います。
- js-sys: JavaScript の API を Rust から使うためのクレート
- wasm-bindgen: Rust と JavaScript の相互運用を可能にするためのクレート
- web-sys: Web API を Rust から使うためのクレート
3. lib.rs の編集
2D Canvas にあるコードを丸っとコピペします。
use std::f64;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
fn start() {
let document = web_sys::window().unwrap().document().unwrap();
let canvas = document.get_element_by_id("Canvas").unwrap();
let canvas: web_sys::HtmlCanvasElement = canvas
.dyn_into::<web_sys::HtmlCanvasElement>()
.map_err(|_| ())
.unwrap();
let context = canvas
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<web_sys::CanvasRenderingContext2d>()
.unwrap();
context.begin_path();
// Draw the outer circle.
context
.arc(75.0, 75.0, 50.0, 0.0, f64::consts::PI * 2.0)
.unwrap();
// Draw the mouth.
context.move_to(110.0, 75.0);
context.arc(75.0, 75.0, 35.0, 0.0, f64::consts::PI).unwrap();
// Draw the left eye.
context.move_to(65.0, 65.0);
context
.arc(60.0, 65.0, 5.0, 0.0, f64::consts::PI * 2.0)
.unwrap();
// Draw the right eye.
context.move_to(95.0, 65.0);
context
.arc(90.0, 65.0, 5.0, 0.0, f64::consts::PI * 2.0)
.unwrap();
context.stroke();
}
let canvas = document.get_element_by_id("Canvas").unwrap();
の部分で、HTML の Canvas 要素を取得しています。
4. wasm-bindgen-cli のインストール
wasm-bindgen-cli というコマンドラインツールをインストールします。
cargo install wasm-bindgen-cli
5. ビルド
※プロジェクトをwasm32で作っています
.wasm ファイルを作成します。
cargo build --target wasm32-unknown-unknown
wasm32.wasm と wasm32.d が作成されます。
wasm-bindgen-cli を使うことで、.js ファイルを作成します。
ブラウザで表示するために --target web を指定します。
wasm-bindgen .\target\wasm32-unknown-unknown\debug\wasm32.wasm --out-dir .\target\wasm32-unknown-unknown\debug\ --target web
--out-dir で出力先を指定します。
出力先に index.html があり、 Docker からアクセスできる場所に配置します。
wasm32.d.ts、wasm32.js、wasm32_bg.wasm、wasm32_bg.wasm.d.ts が作成されます。
bg は "bindings generated"(バインディング付き) の意味のようです。
wasm32_bg.wasm は Rust コードを wasm-bindgen 経由でコンパイルした WebAssembly バイナリ
wasm32.js は wasm32_bg.wasm をロード&バインドする JavaScript ローダー(Rust の関数を JS 経由で呼び出せるようにする)
wasm32.d.ts は wasm32.js の型定義ファイル(TypeScript用)
wasm32_bg.wasm.d.ts は wasm32_bg.js に対応する補助的な TypeScript 型定義ファイル
6. index.html の編集
body タグの中に、canvas 要素を追加し、wasm-bindgen で作成した .js ファイルを読み込みます。
<body>
<h1>WASM Example</h1>
<canvas id="Canvas" width="320" height="240"></canvas>
<script type="module">
import init, { start } from './wasm32.js';
async function run() {
await init();
start();
}
run();
</script>
</body>
7. ブラウザにて確認
以下が表示されます。(Chromeで確認)
8. まとめ
今回は、Rust と WebAssembly を使って Canvas に描画してみました。
wasm-bindgen を使うことで、Rust から JavaScript の関数を呼び出すことができるので、Rust から Canvas に描画することができるようです。
次の機会ではもう少し凝った描画をしてみたいと思います。
今回の記事も、Github Copilot が7割くらい書いてくれました。
A. 参考サイト
Rust における wasm-bindgen と wasm-pack と cargo-web と stdweb の違い
2D Canvas
RustのWebAssembly で canvas に描画する
(前編)MDNブロック崩しをJSからRustに移植してWebAssemblyに入門
Rust/wgpuをWebブラウザで動かす
コメント