diff --git a/Cargo.toml b/Cargo.toml index d1fcb8fb2..f7f032271 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ members = [ "examples/paint", "examples/performance", "examples/raytrace-parallel", + "examples/request-animation-frame", "examples/todomvc", "examples/wasm-in-wasm", "examples/wasm2js", diff --git a/examples/request-animation-frame/.gitignore b/examples/request-animation-frame/.gitignore new file mode 100644 index 000000000..f4336279e --- /dev/null +++ b/examples/request-animation-frame/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +request_animation_frame.js +request_animation_frame_bg.js +request_animation_frame_bg.wasm diff --git a/examples/request-animation-frame/Cargo.toml b/examples/request-animation-frame/Cargo.toml new file mode 100644 index 000000000..0e0f0ee04 --- /dev/null +++ b/examples/request-animation-frame/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "request-animation-frame" +version = "0.1.0" +authors = ["The wasm-bindgen Developers"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-bindgen = "0.2.29" + +[dependencies.web-sys] +version = "0.3.4" +features = [ + 'Document', + 'Element', + 'HtmlElement', + 'Node', + 'Window', +] diff --git a/examples/request-animation-frame/README.md b/examples/request-animation-frame/README.md new file mode 100644 index 000000000..489745412 --- /dev/null +++ b/examples/request-animation-frame/README.md @@ -0,0 +1,17 @@ +# web-sys: `requestAnimationFrame` loop + +[View documentation for this example online][dox] or [View compiled example +online][compiled] + +[compiled]: https://rustwasm.github.io/wasm-bindgen/exbuild/request-animation-frame/ +[dox]: https://rustwasm.github.io/wasm-bindgen/examples/request-animation-frame.html + +You can build the example locally with: + +``` +$ ./build.sh +``` + +(or running the commands on Windows manually) + +and then visiting http://localhost:8080 in a browser should run the example! diff --git a/examples/request-animation-frame/build.sh b/examples/request-animation-frame/build.sh new file mode 100755 index 000000000..12609c369 --- /dev/null +++ b/examples/request-animation-frame/build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# For more comments about what's going on here, see the `hello_world` example + +set -ex + +cargo build --target wasm32-unknown-unknown +cargo run --manifest-path ../../crates/cli/Cargo.toml \ + --bin wasm-bindgen -- \ + ../../target/wasm32-unknown-unknown/debug/request_animation_frame.wasm --out-dir . +npm install +npm run serve diff --git a/examples/request-animation-frame/index.html b/examples/request-animation-frame/index.html new file mode 100644 index 000000000..5c5ad9f33 --- /dev/null +++ b/examples/request-animation-frame/index.html @@ -0,0 +1,8 @@ + + + + + +

A greeting from rust looks like...

+ + diff --git a/examples/request-animation-frame/index.js b/examples/request-animation-frame/index.js new file mode 100644 index 000000000..ea5b06681 --- /dev/null +++ b/examples/request-animation-frame/index.js @@ -0,0 +1,4 @@ +// For more comments about what's going on here, check out the `hello_world` +// example +import('./request_animation_frame') + .catch(console.error); diff --git a/examples/request-animation-frame/package.json b/examples/request-animation-frame/package.json new file mode 100644 index 000000000..806119cdb --- /dev/null +++ b/examples/request-animation-frame/package.json @@ -0,0 +1,13 @@ +{ + "scripts": { + "build": "webpack", + "serve": "webpack-dev-server" + }, + "devDependencies": { + "text-encoding": "^0.7.0", + "html-webpack-plugin": "^3.2.0", + "webpack": "^4.11.1", + "webpack-cli": "^3.1.1", + "webpack-dev-server": "^3.1.0" + } +} diff --git a/examples/request-animation-frame/src/lib.rs b/examples/request-animation-frame/src/lib.rs new file mode 100644 index 000000000..fd83b6843 --- /dev/null +++ b/examples/request-animation-frame/src/lib.rs @@ -0,0 +1,57 @@ +use std::cell::RefCell; +use std::rc::Rc; +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; + +fn window() -> web_sys::Window { + web_sys::window().expect("no global `window` exists") +} + +fn request_animation_frame(f: &Closure) { + window() + .request_animation_frame(f.as_ref().unchecked_ref()) + .expect("should register `requestAnimationFrame` OK"); +} + +fn document() -> web_sys::Document { + window() + .document() + .expect("should have a document on window") +} + +fn body() -> web_sys::HtmlElement { + document().body().expect("document should have a body") +} + +// This function is automatically invoked after the wasm module is instantiated. +#[wasm_bindgen(start)] +pub fn run() -> Result<(), JsValue> { + let f = Rc::new(RefCell::new(None)); + let g = f.clone(); + + { + let mut i = 0; + *g.borrow_mut() = Some(Closure::wrap(Box::new(move || { + if i > 300 { + body().set_text_content(Some("All done!")); + + // Drop our handle to this closure so that it will get cleaned + // up once we return. + let _ = f.borrow_mut().take(); + return; + } + + // Set the body's text content to how many times this + // requestAnimationFrame callback has fired. + i += 1; + let text = format!("requestAnimationFrame has been called {} times.", i); + body().set_text_content(Some(&text)); + + // Schedule ourself for another requestAnimationFrame callback. + request_animation_frame(f.borrow().as_ref().unwrap()); + }) as Box)); + } + + request_animation_frame(g.borrow().as_ref().unwrap()); + Ok(()) +} diff --git a/examples/request-animation-frame/webpack.config.js b/examples/request-animation-frame/webpack.config.js new file mode 100644 index 000000000..f15dc6b56 --- /dev/null +++ b/examples/request-animation-frame/webpack.config.js @@ -0,0 +1,23 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const webpack = require('webpack'); + +module.exports = { + entry: './index.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'index.js', + }, + plugins: [ + new HtmlWebpackPlugin({ + template: "index.html" + }), + // Have this example work in Edge which doesn't ship `TextEncoder` or + // `TextDecoder` at this time. + new webpack.ProvidePlugin({ + TextDecoder: ['text-encoding', 'TextDecoder'], + TextEncoder: ['text-encoding', 'TextEncoder'] + }) + ], + mode: 'development' +}; diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 5ed5b1e51..4cc7f917d 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -25,6 +25,7 @@ - [web-sys: `canvas` Julia set](./examples/julia.md) - [web-sys: WebAudio](./examples/web-audio.md) - [web-sys: WebGL](./examples/webgl.md) + - [web-sys: `requestAnimationFrame`](./examples/request-animation-frame.md) - [web-sys: A Simple Paint Program](./examples/paint.md) - [Parallel Raytracing](./examples/raytrace.md) - [web-sys: A TODO MVC App](./examples/todomvc.md) diff --git a/guide/src/examples/request-animation-frame.md b/guide/src/examples/request-animation-frame.md new file mode 100644 index 000000000..23d48a0c3 --- /dev/null +++ b/guide/src/examples/request-animation-frame.md @@ -0,0 +1,26 @@ +# `web-sys`: A `requestAnimationFrame` Loop + +[View full source code][code] or [view the compiled example online][online] + +[online]: https://rustwasm.github.io/wasm-bindgen/exbuild/request-animation-frame/ +[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/request-animation-frame + +This is an example of a `requestAnimationFrame` loop using the `web-sys` crate! +It renders a count of how many times a `requestAnimationFrame` callback has been +invoked and then it breaks out of the `requestAnimationFrame` loop after 300 +iterations. + +## `Cargo.toml` + +You can see here how we depend on `web-sys` and activate associated features to +enable all the various APIs: + +```toml +{{#include ../../../examples/request-animation-frame/Cargo.toml}} +``` + +## `src/lib.rs` + +```rust +{{#include ../../../examples/request-animation-frame/src/lib.rs}} +```