Posted at

wasmからDOMを操作してSVGを描画する

wasm-bindgen / DOM Hello World!を改造してSVGを出力してみます。全体のコードは以下にあります

https://github.com/termoshtt/wasm-svg-example


準備

npmとwasm-packをインストールしておきます。

cargo install wasm-pack

npmのインストール方法は環境に合わせて適当に構築してください(詳しくないので丸投げ)


web-sys

web-sysはwasm-bindgenでのsubcrateで、


  • DOM

  • Web Audio

  • 2D canvas

  • Web GL

  • fetch

の機能からなる低水準のAPIです。今回使うのはDOMの部分で、これによりDOMを操作してSVGを挿入する事が出来ます。ますweb-sys crateをCargo.tomlに追加してみましょう:


Cargo.toml

[package]

name = "dom"
version = "0.1.0"
authors = ["The wasm-bindgen Developers"]
edition = "2018"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.48"

[dependencies.web-sys]
version = "0.3.4"
features = [
'Document',
'Element',
'HtmlElement',
'SvgElement', # 追加
'SvgCircleElement', # 追加
'Node',
'Window',
]


これは上述のサンプルからコピペしたものですが、一応SVG周りの使う要素をfeaturesに追加しておきました。これは現行では非常にたくさんのfeaturesが設定されていますが、将来的にはまとめたのを作るという方針のようです。


SVGを挿入する

まず空っぽのHTMLを用意します

<html>

<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<p>SVG from rust/wasm!</p>
</body>
</html>

この<p>要素の下にSVGを追加する事を目指しましょう。

use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let body = document.body().expect("document should have a body");

// SVGの描画領域を作る
let svg = document.create_element_ns(Some("http://www.w3.org/2000/svg"), "svg")?;
svg.set_attribute("width", "100")?;
svg.set_attribute("hight", "100")?;
svg.set_attribute("viewBox", "0 0 100 100")?;

// 円を描画
let circle = document.create_element_ns(Some("http://www.w3.org/2000/svg"), "circle")?;
circle.set_attribute("cx", "50")?;
circle.set_attribute("cy", "50")?;
circle.set_attribute("r", "20")?;
circle.set_attribute("stroke", "black")?;
circle.set_attribute("fill", "red")?;
svg.append_child(&circle)?;
body.append_child(&svg)?;

Ok(())
}

はまりポイントとしては、svgcircleを作る際にcreate_elementではなく、create_element_nsを使う必要がある事です。

これをコンパイルして実行するには

npm run serve

とします。npm関係の設定はほぼ全て元のサンプルそのままですので、詳しくはrust wasm bookwasm-bindgen guideを見てください。


最後に