web-sys: canvas Julia set - The wasm-bindgen
Guide (original) (raw)
- Introduction
- 1. Examples
- 1.1. Hello, World!
- 1.2. Using console.log
- 1.3. Small Wasm files
- 1.4. Without a Bundler
- 1.5. Synchronous Instantiation
- 1.6. Importing functions from JS
- 1.7. Working with char
- 1.8. js-sys: WebAssembly in WebAssembly
- 1.9. web-sys: DOM hello world
- 1.10. web-sys: Closures
- 1.11. web-sys: performance.now
- 1.12. web-sys: using fetch
- 1.13. web-sys: Weather report
- 1.14. web-sys: canvas hello world
- 1.15. web-sys: canvas Julia set
- 1.16. web-sys: WebAudio
- 1.17. web-sys: WebGL
- 1.18. web-sys: WebSockets
- 1.19. web-sys: WebRTC DataChannel
- 1.20. web-sys: requestAnimationFrame
- 1.21. web-sys: A Simple Paint Program
- 1.22. web-sys: Wasm in Web Worker
- 1.23. Parallel Raytracing
- 1.24. Wasm Audio Worklet
- 1.25. web-sys: A TODO MVC App
- 2. Reference
- 2.1. Deployment
- 2.2. JS snippets
- 2.3. Static JS Objects
- 2.4. Passing Rust Closures to JS
- 2.5. Receiving JS Closures in Rust
- 2.6. Promises and Futures
- 2.7. Iterating over JS Values
- 2.8. Arbitrary Data with Serde
- 2.9. Accessing Properties of Untyped JS Values
- 2.10. Working with Duck-Typed Interfaces
- 2.11. Command Line Interface
- 2.12. Optimizing for Size
- 2.13. Supported Rust Targets
- 2.14. Supported Browsers
- 2.15. Support for Weak References
- 2.16. Support for Reference Types
- 2.17. Supported Types
- 2.18. #[wasm_bindgen] Attributes
- 2.18.1. On JavaScript Imports
- 2.18.1.1. catch
- 2.18.1.2. constructor
- 2.18.1.3. extends
- 2.18.1.4. getter and setter
- 2.18.1.5. final
- 2.18.1.6. indexing_getter, indexing_setter, and indexing_deleter
- 2.18.1.7. js_class = "Blah"
- 2.18.1.8. js_name
- 2.18.1.9. js_namespace
- 2.18.1.10. method
- 2.18.1.11. module = "blah"
- 2.18.1.12. raw_module = "blah"
- 2.18.1.13. no_deref
- 2.18.1.14. static_method_of = Blah
- 2.18.1.15. structural
- 2.18.1.16. typescript_type
- 2.18.1.17. variadic
- 2.18.1.18. vendor_prefix
- 2.18.1.1. catch
- 2.18.2. On Rust Exports
- 2.18.2.1. constructor
- 2.18.2.2. js_name = Blah
- 2.18.2.3. js_class = Blah
- 2.18.2.4. readonly
- 2.18.2.5. skip
- 2.18.2.6. skip_jsdoc
- 2.18.2.7. start
- 2.18.2.8. main
- 2.18.2.9. typescript_custom_section
- 2.18.2.10. getter and setter
- 2.18.2.11. inspectable
- 2.18.2.12. skip_typescript
- 2.18.2.13. getter_with_clone
- 2.18.2.14. unchecked_return_type and unchecked_param_type
- 2.18.2.15. return_description and param_description
- 2.18.2.1. constructor
- 3. web-sys
- 4. Testing with wasm-bindgen-test
- 5. Contributing to wasm-bindgen
- 5.2. Internal Design
- 5.3. js-sys
- 5.4. web-sys
- 5.5. Publishing
- 5.6. Team
The `wasm-bindgen` Guide
View full source code or view the compiled example online
While not showing off a lot of web_sys
API surface area, this example shows a neat fractal that you can make!
A small bit of glue is added for this example
import('./pkg')
.then(wasm => {
const canvas = document.getElementById('drawing');
const ctx = canvas.getContext('2d');
const realInput = document.getElementById('real');
const imaginaryInput = document.getElementById('imaginary');
const renderBtn = document.getElementById('render');
renderBtn.addEventListener('click', () => {
const real = parseFloat(realInput.value) || 0;
const imaginary = parseFloat(imaginaryInput.value) || 0;
wasm.draw(ctx, 600, 600, real, imaginary);
});
wasm.draw(ctx, 600, 600, -0.15, 0.65);
})
.catch(console.error);
The bulk of the logic is in the generation of the fractal
# #![allow(unused_variables)]
#fn main() {
use std::ops::Add;
use wasm_bindgen::prelude::*;
use wasm_bindgen::Clamped;
use web_sys::{CanvasRenderingContext2d, ImageData};
#[wasm_bindgen]
pub fn draw(
ctx: &CanvasRenderingContext2d,
width: u32,
height: u32,
real: f64,
imaginary: f64,
) -> Result<(), JsValue> {
// The real workhorse of this algorithm, generating pixel data
let c = Complex { real, imaginary };
let data = get_julia_set(width, height, c);
let data = ImageData::new_with_u8_clamped_array_and_sh(Clamped(&data), width, height)?;
ctx.put_image_data(&data, 0.0, 0.0)
}
fn get_julia_set(width: u32, height: u32, c: Complex) -> Vec<u8> {
let mut data = Vec::new();
let param_i = 1.5;
let param_r = 1.5;
let scale = 0.005;
for x in 0..width {
for y in 0..height {
let z = Complex {
real: y as f64 * scale - param_r,
imaginary: x as f64 * scale - param_i,
};
let iter_index = get_iter_index(z, c);
data.push((iter_index / 4) as u8);
data.push((iter_index / 2) as u8);
data.push(iter_index as u8);
data.push(255);
}
}
data
}
fn get_iter_index(z: Complex, c: Complex) -> u32 {
let mut iter_index: u32 = 0;
let mut z = z;
while iter_index < 900 {
if z.norm() > 2.0 {
break;
}
z = z.square() + c;
iter_index += 1;
}
iter_index
}
#[derive(Clone, Copy, Debug)]
struct Complex {
real: f64,
imaginary: f64,
}
impl Complex {
fn square(self) -> Complex {
let real = (self.real * self.real) - (self.imaginary * self.imaginary);
let imaginary = 2.0 * self.real * self.imaginary;
Complex { real, imaginary }
}
fn norm(&self) -> f64 {
(self.real * self.real) + (self.imaginary * self.imaginary)
}
}
impl Add<Complex> for Complex {
type Output = Complex;
fn add(self, rhs: Complex) -> Complex {
Complex {
real: self.real + rhs.real,
imaginary: self.imaginary + rhs.imaginary,
}
}
}
#}