WebAssembly (WASM) یک قالب باینری برای کد قابل اجرا در مرورگرها است. در این مقاله، ما یک وباپلیکیشن ساده با استفاده از کتابخانه React خواهیم ساخت، بخشی از کد JavaScript خود را به WASM نوشته و کمپایل خواهیم کرد و سپس آن را به برنامه لینک خواهیم کرد. ما یک برنامه حداقلی با کتابخانه React نیاز داریم. من نحوه ساخت آن را از ابتدا توضیم نخواهم داد. برنامه موجود در این لینک برای نیازهای ما کافیست.
آمادهسازی
برای شروع این برنامه حداقلی React، میتوانیم آن را کپی کنیم:
git clone git@github.com:rwieruch/minimal-react-webpack-babel-setup.git wasm_react
حال میتوانیم تمام Dependencyها را برای اجرای سرور نصب کنیم:
cd wasm_react
yarn install
yarn start
سپس میتوانید به لینک http://localhost:8080 بروید و ببینید که آیا کار میکند یا نه.
ساخت کامپوننت بوم (Canvas)
کار بعدی که باید انجام دهیم، ساخت یک کامپوننت React جدید با Canvas و اضافه کردن تابع کشیدن (Draw) است.
برای کامپوننت جدید خود، میتوانیم فایل جدید را بسازیم:
touch src/canvas.js
و آن را در این کد قرار دهیم:
// src/canvas.js
import React, {Component} from "react";
class Canvas extends Component {
componentDidMount() {
let canvas = this.refs.canvas.getContext('2d');
canvas.fillRect(0, 0, 100, 100);
}
render() {
return (
<canvas ref="canvas" width={this.props.width} height={this.props.height}/>
)
}
}
export default Canvas;
این کامپوننت، Canvas را با استفاده از پارامترهای دریافتی از props میسازد و پس از آن باید یک مستطیل سیاه در Canvas مورد نظر ببینید.
برای رندر کردن کامپوننت جدید، میتوانیم آن را به src/index.js اضافه کنیم:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Canvas from './canvas';
const title = 'My Minimal React Webpack Babel Setup';
ReactDOM.render(
<Canvas height={500} width={500} />,
document.getElementById('app')
);
module.hot.accept();
حال میتوانید به مرورگر بروید و ببینید که آیا یک مستطیل سیاه دارید یا نه.
فراکتالهای کشیدن
چیز بعدیای که خواهیم کشید، مجموعه Mandelbrot است. در ابتدا، ما آن را با استفاده از JavaScript پیادهسازی خواهیم کرد و سپس هم آن را در WebAssembly مجددا پیادهسازی خواهیم نمود.
حال ما میتوانیم تابع mandelIter را به کامپوننت Canvas خود اضافه کنیم:
// scr/canvas.js
class Canvas extends Component {
//.....
mandelIter(x, y, maxIter) {
let r = x;
let i = y;
for (let a = 0; a < maxIter; a++) {
let tmpr = r * r - i * i + x;
let tmpi = 2 * r * i + y;
r = tmpr;
i = tmpi;
if (r * i > 5) {
return a/maxIter * 100;
}
}
return 0;
}
//.....
پس از آن، میتوانیم دو حلقه به componentDidMount اضافه کنیم، تا در طی تمام پیکسلها در Canvas تکرار (iterate) کنند.
تابع بروزرسانی شده:
// src/canvas.js
componentDidMount() {
let canvas = this.refs.canvas.getContext('2d');
let mag = 200;
let panX = 2;
let panY = 1.25;
let maxIter = 100;
for (let x = 10; x < this.props.height; x++) {
for (let y = 10; y < this.props.width; y++) {
let m = this.mandelIter(x/mag - panX, y/mag - panY, maxIter);
canvas.fillStyle = (m === 0) ? '#000' : 'hsl(0, 100%, ' + m + '%)';
canvas.fillRect(x, y, 1,1);
}
}
}
پس از این تغییر، باید مجموعه Mandelbrot را بر روی صفحه ببینید:
ظاهر خوبی دارد، نه؟
پیادهسازی در WebAssembly
حال میتوانیم یک تابع mandelIter را در WebAssembly پیادهسازی کنیم. ما میتوانیم این کار با استفاده از C++، Rust یا Go انجام دهیم. اما در اینجا از C++ و یک کمپایل کننده WebAssembly آنلاین، به نام WebAssembly Explorer استفاده خواهیم کرد.
تابع mandelIter پیادهسازی شده در C++:
float mandelIter(float x, float y, int maxIter) {
float r = x;
float i = y;
for (int a = 0; a < maxIter; a++) {
float tmpr = r * r - i * i + x;
float tmpi = 2 * r * i + y;
r = tmpr;
i = tmpi;
if (r * i > 5) {
return a/(float) maxIter * 100;
}
}
return 0;
}
تابع ما پس از کمپایل شدن یک نام عجیب دارد: _z10mandelIterffi. ما از این نام در کد JavaScript خود استفاده خواهیم کرد.
پس از کمپایل کردن، میتوانیم فایل مورد نظر را دانلود کرده و در پوشه src قرار دهیم. من آن را fractal.wasm نامگذاری کردهام.
برای استفاده از wasm در React، فقط باید کامپوننت Canvas را import کنید:
// src/canvas.js
import React, {Component} from "react";
const wasm = import("./fractal.wasm");
class Canvas extends Component {
قدم بعدی هم بروزرسانی تابع componentDidMount است:
// src/canvas.js
componentDidMount() {
wasm.then(wasm => {
const mandelIterWASM = wasm._Z10mandelIterffi;
let canvas = this.refs.canvas.getContext('2d');
let mag = 200;
let panX = 2;
let panY = 1.25;
let maxIter = 100;
for (let x = 10; x < this.props.height; x++) {
for (let y = 10; y < this.props.width; y++) {
// let m = this.mandelIter(x/mag - panX, y/mag - panY, maxIter);
let m = mandelIterWASM(x/mag - panX, y/mag - panY, maxIter);
canvas.fillStyle = (m === 0) ? '#000' : 'hsl(0, 100%, ' + m + '%)';
canvas.fillRect(x, y, 1,1);
}
}
});
}
حال برای کشیدن بر روی Canvas، ما از تابع پیادهسازی شده در WebAssembly استفاده میکنیم.
شما میتوانید متغیرهای mag، panX و panY را دستکاری کنید تا یک فرم دیگر از فراکتالها را بسازید:
کل کد استفاده شده را میتوانید در مخزن این برنامه بر روی GitHub بیابید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید