1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#![deny(missing_docs, missing_debug_implementations)]
use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
#[derive(Debug)]
pub struct AnimationFrame {
render_id: i32,
_closure: Closure<dyn Fn(JsValue)>,
callback_wrapper: Rc<RefCell<Option<CallbackWrapper>>>,
}
struct CallbackWrapper(Box<dyn FnOnce(f64) + 'static>);
impl fmt::Debug for CallbackWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("CallbackWrapper")
}
}
impl Drop for AnimationFrame {
fn drop(&mut self) {
if self.callback_wrapper.borrow_mut().is_some() {
web_sys::window()
.unwrap_throw()
.cancel_animation_frame(self.render_id)
.unwrap_throw()
}
}
}
pub fn request_animation_frame<F>(callback_once: F) -> AnimationFrame
where
F: FnOnce(f64) + 'static,
{
let callback_wrapper = Rc::new(RefCell::new(Some(CallbackWrapper(Box::new(callback_once)))));
let callback: Closure<dyn Fn(JsValue)> = {
let callback_wrapper = Rc::clone(&callback_wrapper);
Closure::wrap(Box::new(move |v: JsValue| {
let time: f64 = v.as_f64().unwrap_or(0.0);
let callback = callback_wrapper.borrow_mut().take().unwrap().0;
callback(time);
}))
};
let render_id = web_sys::window()
.unwrap_throw()
.request_animation_frame(callback.as_ref().unchecked_ref())
.unwrap_throw();
AnimationFrame {
render_id,
_closure: callback,
callback_wrapper,
}
}