抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

使用Rust与WASM画三角形

概念

WASM是一种二进制格式,我们可以将一些语言编译为这种格式,使得代码可以在浏览器中运行

与Typescript转JavaScript不同,WASM是一种编译好的二进制,性能会比那些“编一句运行一句的代码”性能好

WASM最初是为了C/C++设计的,但也很适合使用Rust,如果你是一个Rust信徒,这套逻辑很适合你

环境安装

Windows 11 + Winget

winget install node.js
winget install rustup

下载wasm-pack:[链接](wasm-pack (rustwasm.github.io))

项目初始化

npm init rust-webpack
npm install
npm start

rust_init

此时会自动弹出一个网页,按F12可以发现,控制台输出了Hello World!

wasm_init

绘制三角形

static/index.html中添加一个canvas

<body>
+ <canvas id="canvas" tabindex="0" height="600" width="600">
+ Your browser does not support the canvas.
+ </canvas>
<script src="index.js"></script>
</body>

Cargo.toml中添加web-sys依赖

[dependencies.web-sys]
version = "0.3.22"
-features = ["console"]
+features = ["console", "Window", "Document", "HtmlCanvasElement", "CanvasRenderingContext2d", "Element"]

src/lib.rs中添加绘制命令

wasm_bindgen会export main_js,以便JavaScript调用

#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
+ let window = web_sys::window().unwrap();
+ let document = window.document().unwrap();
+ let canvas = document
+ .get_element_by_id("canvas")
+ .unwrap()
+ .dyn_into::<web_sys::HtmlCanvasElement>()
+ .unwrap();
+ let context = canvas
+ .get_context("2d")
+ .unwrap()
+ .unwrap()
+ .dyn_into::<web_sys::CanvasRenderingContext2d>()
+ .unwrap();
+ context.move_to(300.0, 0.0); // top of triangle
+ context.begin_path();
+ context.line_to(0.0, 600.0); // bottom left of triangle
+ context.line_to(600.0, 600.0); // bottom right of triangle
+ context.line_to(300.0, 0.0); // back to top of triangle
+ context.close_path();
+ context.stroke();
+ context.fill();

// Your code goes here!
console::log_1(&JsValue::from_str("Hello world!"));

Ok(())
}

保存代码,即可触发热更(前端就是好啊)

绘制三角形

绘制分形体

添加分形体代码

fn draw_triangle(context: &web_sys::CanvasRenderingContext2d, points: [(f64, f64); 3]) {
let [top, left, right] = points;
context.move_to(top.0, top.1);
context.begin_path();
context.line_to(left.0, left.1);
context.line_to(right.0, right.1);
context.line_to(top.0, top.1);
context.close_path();
context.stroke();
}

fn midpoint(point_1: (f64, f64), point_2: (f64, f64)) -> (f64, f64) {
((point_1.0 + point_2.0) / 2.0, (point_1.1 + point_2.1) / 2.0)
}

fn sierpinski(context: &web_sys::CanvasRenderingContext2d, points: [(f64, f64); 3], depth: u8) {
draw_triangle(&context, points);
let depth = depth-1;
let [top, left, right] = points;
if depth > 0 {
let left_middle = midpoint(top, left);
let right_middle = midpoint(top, right);
let bottom_middle = midpoint(left, right);
sierpinski(&context, [top, left_middle, right_middle], depth);
sierpinski(&context, [left_middle, left, bottom_middle], depth);
sierpinski(&context, [right_middle, bottom_middle, right], depth);
}

}

删去之前所有绘制内容,改为sierpinski

#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let canvas = document
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
let context = canvas
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<web_sys::CanvasRenderingContext2d>()
.unwrap();

sierpinski(&context, [(300.0, 0.0), (0.0, 600.0), (600.0, 600.0)], 5);

Ok(())
}

绘制分形体

评论