I built this particle animation in rust + wasm and javascript and test it for 50000 x 8 times particle the javascript version is faster then rust + wasm is there a way to make it fast faster then js
use wasm_bindgen::prelude::*;
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, MouseEvent};
use js_sys::Math;
use std::f64;
use wasm_bindgen::JsCast;
fn random_int(min: i32, max: i32) -> f64 {
Math::random() * (max - min) as f64 + min as f64
}
#[wasm_bindgen]
pub struct Particle {
x: f64,
y: f64,
size: f64,
sx: f64,
sy: f64,
color: String,
}
#[wasm_bindgen]
impl Particle {
pub fn new(x: f64, y: f64) -> Particle {
Particle {
x,
y,
size: random_int(10, 15),
sx: random_int(-3, 3),
sy: random_int(-3, 3),
color: format!("hsl({}, 100%, 50%)", random_int(0, 360)),
}
}
pub fn draw(&self, ctx: &CanvasRenderingContext2d) {
ctx.begin_path();
ctx.set_fill_style(&JsValue::from_str(&self.color));
ctx.arc(self.x, self.y, self.size, 0.0, 2.0 * f64::consts::PI).unwrap();
ctx.fill();
ctx.close_path();
}
pub fn update(&mut self, ctx: &CanvasRenderingContext2d) {
self.draw(ctx);
self.x += self.sx;
self.y += self.sy;
if self.size > 0.2 {
self.size -= 0.08;
}
}
}
#[derive(Clone, Copy)]
struct Mouse {
x: f64,
y: f64,
}
#[wasm_bindgen]
pub fn start() -> Result<(), JsValue> {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let canvas: HtmlCanvasElement = document
.get_element_by_id("myCanvas")
.unwrap()
.dyn_into::<HtmlCanvasElement>()?;
let ctx: CanvasRenderingContext2d = canvas
.get_context("2d")?
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()?;
let particles = std::rc::Rc::new(std::cell::RefCell::new(Vec::new()));
let mouse = std::rc::Rc::new(std::cell::RefCell::new(Mouse { x: 0.0, y: 0.0 }));
let particles_clone = particles.clone();
let mouse_clone = mouse.clone();
let click_closure = Closure::wrap(Box::new(move |event: MouseEvent| {
let mut mouse = mouse_clone.borrow_mut();
mouse.x = event.client_x() as f64;
mouse.y = event.client_y() as f64;
let mut particles = particles_clone.borrow_mut();
// Changed to 500 particles per click
for _ in 0..50 {
particles.push(Particle::new(mouse.x, mouse.y));
}
}) as Box<dyn FnMut(MouseEvent)>);
canvas.add_event_listener_with_callback("mousemove", click_closure.as_ref().unchecked_ref())?;
// canvas.add_event_listener_with_callback("click", click_closure.as_ref().unchecked_ref())?;
click_closure.forget();
let f = std::rc::Rc::new(std::cell::RefCell::new(None::<Closure<dyn FnMut()>>));
let g = f.clone();
let particles_clone = particles.clone();
*g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
let canvas = ctx.canvas().unwrap();
ctx.clear_rect(0.0, 0.0, canvas.width() as f64, canvas.height() as f64);
let mut particles = particles_clone.borrow_mut();
// Remove particles that are too small
particles.retain(|particle| particle.size > 0.2);
// Update remaining particles
for particle in particles.iter_mut() {
particle.update(&ctx);
}
web_sys::window()
.unwrap()
.request_animation_frame(f.borrow().as_ref().unwrap().as_ref().unchecked_ref())
.unwrap();
}) as Box<dyn FnMut()>));
web_sys::window()
.unwrap()
.request_animation_frame(g.borrow().as_ref().unwrap().as_ref().unchecked_ref())
.unwrap();
Ok(())
}