Skip to content

Instantly share code, notes, and snippets.

@mizchi
Last active July 22, 2023 06:24
Show Gist options
  • Save mizchi/1ef81dce7e7529c9a4678e0d1300c820 to your computer and use it in GitHub Desktop.
Save mizchi/1ef81dce7e7529c9a4678e0d1300c820 to your computer and use it in GitHub Desktop.
use std::{rc::Rc, sync::Mutex};
use rand::Rng;
use wasm_bindgen::prelude::*;
fn draw_triangle(context: &web_sys::CanvasRenderingContext2d, points: [(f64, f64); 3], color: (u8, u8, u8)) {
let [top, left, right] = points;
let color_str = format!("rgb({},{},{})", color.0, color.1, color.2);
context.set_fill_style(&wasm_bindgen::JsValue::from_str(&color_str));
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();
context.fill();
}
fn midpoint(p1: (f64, f64), p2: (f64, f64)) -> (f64, f64) {
let (x1, y1) = p1;
let (x2, y2) = p2;
((x1 + x2) / 2.0, (y1 + y2) / 2.0)
}
fn sierpinski(context: &web_sys::CanvasRenderingContext2d, points: [(f64, f64); 3], color: (u8, u8, u8), depth: u8) {
let [top, left, right] = points;
draw_triangle(&context, [
top, left, right
], color);
let depth = depth - 1;
if depth > 0 {
let left_mid = midpoint(top, left);
let right_mid = midpoint(top, right);
let bottom_mid = midpoint(left, right);
let mut rng = rand::thread_rng();
let next_color = (
rng.gen_range(0..255),
rng.gen_range(0..255),
rng.gen_range(0..255)
);
sierpinski(context, [top, left_mid, right_mid], next_color, depth);
sierpinski(context, [left_mid, left, bottom_mid], next_color, depth);
sierpinski(context, [right_mid, bottom_mid, right], next_color, depth);
}
}
pub fn main() -> Result<(), JsValue> {
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
#[cfg(debug_assertions)]
wasm_logger::init(wasm_logger::Config::default());
log::debug!("Hello, world!");
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().dyn_into::<web_sys::CanvasRenderingContext2d>().unwrap();
sierpinski(&context, [
(300.0, 0.0),
(0.0, 600.0),
(600.0, 600.0)
], (0,255,0), 5);
wasm_bindgen_futures::spawn_local(async move {
let image = web_sys::HtmlImageElement::new().unwrap();
let (success_tx, success_rx) = futures::channel::oneshot::channel::<Result<(), JsValue>>();
let success_tx = Rc::new(Mutex::new(Some(success_tx)));
let error_tx = Rc::clone(&success_tx);
let callback = Closure::once(move || {
log::debug!("Loaded");
if let Some(success_tx) = success_tx.lock().unwrap().take() {
success_tx.send(Ok(())).unwrap();
}
});
let error_callback = Closure::once(move |err| {
log::debug!("Error");
if let Some(error_tx) = error_tx.lock().ok().and_then(|mut opt| opt.take()) {
error_tx.send(Err(err)).unwrap();
}
});
image.set_onload(Some(callback.as_ref().unchecked_ref()));
image.set_onerror(Some(error_callback.as_ref().unchecked_ref()));
callback.forget();
error_callback.forget();
image.set_src("/assets/resized/rhb/Idle (1).png");
let _ = success_rx.await.unwrap();
context.draw_image_with_html_image_element(&image, 0.0, 0.0).unwrap();
});
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment