全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-01-23_前端仔,用rust来写canvas

您的位置:首页 >> 新闻 >> 行业资讯

前端仔,用rust来写canvas 点击关注公众号,“技术干货”及时达! 一. 前言以前一直有一些高性能的渲染问题困扰着我,比如canvas渲染百万、千万级数据,以及一些图片像素的操作等。虽然现在的js也给了很多优化的方案(比如web workers)。但是说到底还是有语言方面的局限性,直到我看到了wasm(WebAssembly),可以在客户端处理二进制程序。 二. wasm介绍2.1 什么是wasm简单来说是一种为网络而生的新型代码格式,旨在提供一种比传统 JavaScript 更快的执行速度,可以大大的提升网络的性能,这个提升不是传统意义上的优化,而是真正意义上的从根本上完成代码运行质的飞跃。 2.2 wasm的优点提高性能wasm允许浏览器中运行高性能代码,其运行速度接近原生。当我们前端需要进行处理大型密集的计算工作,以及实时图片处理等。跨语言支持wasm并不是什么特定的编译语言,而是一种平台。开发者可以使用C,C++,Rust,go等编写代码,然后转为wasm,最后在浏览器中运行。与js功能互补wasm出现并不是为了取代js,而是为了更好的为js提供服务。在一些特定的环境(比如可视化等)js可以做为交互,wasm可以做为密集计算。优化资源占用wasm的设计是为了占用较少的内存,这使得它非常适合资源有限的设备,如手机等移动设备。通过减少内存占用,Wasm可以帮助前端应用在各种类型的设备上都能顺利运行,提升用户体验。2.3 如何在前端中使用现代浏览器是支持直接兼容.wasm文件的。所以我们就是通过go、Rust等语言去编写wasm文件,然后通过编译器转为为.wasm文件在前端调用。 三. Rust的使用简单的介绍一下Rust的使用吧。 3.1 rust安装按照官网的安装流程来就好。 curl https://sh.rustup.rs -sSf | sh 安装完成之后,我们在终端输入: rustc --version cargo --version 出现这两个版本,表示安装成功! 这里面要注意一下:rustc和cargo都是Rust的编程工具,但是功能不同。 rustc是Rust的源代码编译器,把Rust源码编译成可执行文件或库。cargo是Rust包管理工具(可以理解为npm)。主要目的就是管理Rust的项目依赖,自动生成构建脚本等。3.2 rust项目结构分析完成安装之后,我们可以试一下新建一个Rust项目。 cargo new my_project --lib --lib是cargo命令行工具的一个选项,用于指示Cargo创建一个新的库(library)项目。 我们看一下文件目录: 主要核心是这两个lib.rs、Cargo.toml。 lib.ts源码的入口地方。Cargo.toml项目的依赖管理文件。四. Rust转为wasm简单了解了一下Rust之后,就有个疑问?Rust如何编译为可以执行的wasm文件?答案就是:wasm-bindgen 4.1 wasm-bindgen是一个强大的工具链,旨在简化WebAssembly(WASM)模块与JavaScript之间的交互。主要目的是将Rust的性能优势引入Web开发中,并实现与JavaScript的无缝集成?。 主要功能就是自动生成可以必要的绑定和胶水代码,确保Rust和js之间可以正常的平滑通信。 简单来说,wasm-bindgen就是一个桥梁,沟通Rust和js之间运行的桥梁。 通过wasm-bindgen编译的代码可以在js中使用。 4.2 wasm-bindgen使用如何在rust中使用呢?这就要用到我们之前说的Cargo.toml文件了。把wasm-bindgen的依赖声明到对应的文件中: [package]name = "my_wasm_project"version = "0.1.0"edition = "els" [lib]crate-type = ["cdylib"] [dependencies]wasm-bindgen = "0.2" [dependencies]指定依赖和依赖的版本。 比如:wasm-bindgen的版本为0.2。[package]生成的这个包的一些基本信息。[crate-type]是一个配置项,用于指定当你构建项目时生成的输出类型 。五. 使用Rust生成一个canvas文件5.1 代码简单介绍了Rust的一些基本使用,那下面我们用一个案例来看一下Rust如何生成wasm文件的。 这里用一个简单的例子,通过传入一个canvas实例,然后绘制一个圆。 我们新建一个项目,然后先安装依赖,回到Cargo.toml文件中: [package]name = "my_wasm_project"version = "0.1.0"edition = "2021" [lib]crate-type = ["cdylib"] [dependencies]wasm-bindgen = "0.2"web-sys = { version = "0.3", features = ["Window", "Document", "HtmlCanvasElement", "CanvasRenderingContext2d"] } 主要是看一下dependencies。 wasm-bindgen就是前面说的编译Rust代码的桥梁。 web-sys是一个Rust的标准库,它提供了对Web API的绑定。包括DOM、HTML、CSS、XMLHttpRequest、Fetch API、WebSocket等等。 使得你可以使用 Rust 语言来编写与浏览器环境交互的代码。 features字段指定了你要启用的 Web API 特性。web-sys默认并不包含所有的 Web API,你需要显式地指定你想要使用的那些特性。比如这里我们需要用canvas绘图,就需要显示的指定Document,HtmlCanvasElement,CanvasRenderingContext2d等canvs的特性。 完成配置之后,我们回到lib.rs:编写一段代码。 use wasm_bindgen::prelude::*;use web_sys::{window, Document, HtmlCanvasElement, CanvasRenderingContext2d}; #[wasm_bindgen]pub fn draw_circle(canvas_id: &str) - Result(), JsValue { // 获取全局window对象 let window = window().expect("no global `window` exists"); // 获取document let document = window.document().expect("window should have a document"); // 通过 ID 获取 canvas 元素 let canvas = document.get_element_by_id(canvas_id) .and_then(|e| e.dyn_into::HtmlCanvasElement().ok()) .expect("canvas element not found"); // 设置 canvas 尺寸 canvas.set_width(500); canvas.set_height(500); // 获取 2D 渲染上下文 let context = canvas .get_context("2d") .expect("failed to get context") .unwrap() .dyn_into::CanvasRenderingContext2d() .expect("context is not of type 2d"); // 开始路径 context.begin_path(); // 绘制圆 context.arc(250.0, 250.0, 100.0, 0.0, std::f64::consts::PI * 2.0)?; // 设置填充颜色 context.set_fill_style(&JsValue::from_str("blue")); // 填充圆 context.fill(); // 设置描边颜色 context.set_stroke_style(&JsValue::from_str("black")); // 描边圆 context.stroke(); Ok(())} 实现了一个draw_circle方法,然后可以提供在web端使用。 5.2 代码解析看起来上面代码有点懵逼,没关系我们可以一行一行分析一下,确实很难!!!! 5.2.1 use关键字use是把模块,项,或者路径导入当前的目录中。这使得你可以在代码中直接使用这些导入的名称,而不需要每次都写完整的路径。 use std::io;这个意思就是把std下面的io模块导出,就可以直接使用了。 use co::*;这个意思就是把co模块下的全部方法、定义等导出。 use wasm_bindgen::prelude::*;意思就是从【wasm_bindgen】的模块【prelude】中导入所有的内容。 5.2.2 ::操作符在rust中::是一个很重要的操作符,主要用于访问模块、结构体、枚举、函数、常量等的命名空间中的成员。 如下例子: 引用模块中的函数: mod math { pub fn add(a: i32, b: i32) - i32 { a + b } } fn main() { let result = math::add(1, 2); // 使用 :: 引用模块中的函数 println("{}", result); } // 引用枚举中的类型 enum Color { Red = 'red', Blue ='blue' } fn main() { let color = Color::Red; // 使用 :: 引用枚举中的类型 } use web_sys::{window, Document, HtmlCanvasElement, CanvasRenderingContext2d}意思就是:引用web_sys模块中的window, Document, HtmlCanvasElement, CanvasRenderingContext2d使用。 5.2.3 pub关键字pub是访问修饰符,表示“公共”的意思,fn 是函数的关键字。通过 pub fn 定义的函数可以在模块外部被访问和调用。 pub fn draw_circle声明的函数就可以在外部引入使用。 5.2.4 #[wasm_bindgen]使用#[wasm_bindgen]定义的函数,可以使得Rust 代码能够与 JavaScript 无缝交互。通过使用这个属性,你可以轻松地将 Rust 函数导出给 JavaScript 使用,或者从 Rust 代码中调用 JavaScript 函数。 5.2.5 #[wasm_bindgen(start)]表示当前的函数在js中导入使用是自动执行的。 5.2.6 JsValue类型JsValue是 wasm-bindgen 库中的一个类型,用于表示JavaScript中的值。它可以表示任何JavaScript值,如数字、字符串、对象等。在Wasm环境中,JsValue 用于在Rust和JavaScript之间传递数据。 5.2.7 dyn_into将 JavaScript 对象转换为特定的 Rust 类型。这个函数通常用于处理从 JavaScript 传递过来的对象,这些对象可能需要被转换成更具体的 Rust 类型,以便你可以调用该类型特有的方法或访问其属性。 由于 WebAssembly 和 JavaScript 之间的交互是通过接口定义来进行的,有时候你从 JavaScript 接收到的对象可能是通用的类型(如JsValue),但你需要将其转换为特定的 Rust 类型(如HtmlElement或Document)来使用。dyn_into函数提供了这种转换能力,并且它会进行类型检查,确保转换是安全的。 // 尝试将 Node 转换为 HtmlElement let element: HtmlElement = node.dyn_into().map_err(|_| { console_error!("Failed to convert Node to HtmlElement"); }).unwrap();5.2.8 expect通常用于Option和Result类型。它的主要作用是当值为None或Err时提供自定义的错误消息,并触发panic!宏,从而终止程序。说白了,就是Rust的错误处理机制。这也是Rust为什么很安全的原因,每一句话都会有对应的错误处理。 OK,大概了解了一下上面的语法之后,再去看这个方法就很简单了,其实就是一个简单的canvas绘制,只不过函数的写法和一些异常处理变多了。 5.3 项目编译完成代码之后,我们把Rust代码编译为wasm。 wasm-pack build --target pkg 我们会发现在文件夹中多出了几个包: 这个pkg就是在client的运行内容。 六. 在项目中使用我们准备把Rust生成的wasm文件放到vue3.0项目中使用。 新建一个vue3.0项目: npm init vite 然后我们把Rust这个包放到对应的文件夹下面。 完成之后,我们可以在node_modules里面关联一下my_wasm_project下面的pkg包。 pnpm i ./my_wasm_project/pkg 就可以在node_modules完成关联。 为了可以自动编译,然后同步更新node_modules里面内容,我们在package.json里面写一个脚步执行。 "scripts": { "wasm": "cd ./my_wasm_project && wasm-pack build --target web && cd .. && pnpm install ./my_wasm_project/pkg" }, cd ./my_wasm_project进入到my_wasm_project包中。wasm-pack build --target web编译一下。cd .. && pnpm install ./my_wasm_project/pkg回到根目录,然后install一下对应的包。然后在组件里面使用一下: import init, { draw_circle } from 'my_wasm_project/my_wasm_project' onMounted(async () = { await init(); draw_circle('my_canvas') }) 这里要注意一下,需要把引入一个init函数先执行,这个目的是为了先构建wasm的运行环境。 然后执行一下draw_circle方法。 ok,完成啦,一个最简单的canvas在页面中使用。 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2024-03-29_4月营销热点日历 | 愚人节、清明、谷雨、世界地球日、读书日 下一篇:2021-11-26_朋友们,拯救“书荒”神级书单来了!

TAG标签:

17
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价