yew_stdweb/services/
render.rs1use crate::callback::Callback;
5use crate::services::Task;
6use cfg_if::cfg_if;
7use cfg_match::cfg_match;
8use std::fmt;
9cfg_if! {
10 if #[cfg(feature = "std_web")] {
11 #[allow(unused_imports)]
12 use stdweb::{_js_impl, js};
13 use stdweb::unstable::TryInto;
14 use stdweb::Value;
15 } else if #[cfg(feature = "web_sys")] {
16 use crate::utils;
17 use wasm_bindgen::closure::Closure;
18 use wasm_bindgen::{JsCast, JsValue};
19 }
20}
21
22#[must_use = "the task will be cancelled when the task is dropped"]
24pub struct RenderTask(
25 #[cfg(feature = "std_web")] Value,
26 #[cfg(feature = "web_sys")] RenderTaskInner,
27);
28
29#[cfg(feature = "web_sys")]
30struct RenderTaskInner {
31 render_id: i32,
32 #[allow(dead_code)]
33 callback: Closure<dyn Fn(JsValue)>,
34}
35
36impl fmt::Debug for RenderTask {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.write_str("RenderTask")
39 }
40}
41
42#[derive(Default, Debug)]
44pub struct RenderService {}
45
46impl RenderService {
47 pub fn request_animation_frame(callback: Callback<f64>) -> RenderTask {
49 let callback = move |#[cfg(feature = "std_web")] v,
50 #[cfg(feature = "web_sys")] v: JsValue| {
51 let time: f64 = cfg_match! {
52 feature = "std_web" => ({
53 match v {
54 Value::Number(n) => n.try_into().unwrap(),
55 _ => 0.0,
56 }
57 }),
58 feature = "web_sys" => v.as_f64().unwrap_or(0.),
59 };
60 callback.emit(time);
61 };
62 let handle = cfg_match! {
63 feature = "std_web" => js! {
64 var callback = @{callback};
65 var action = function(time) {
66 callback(time);
67 callback.drop();
68 };
69 return {
70 render_id: requestAnimationFrame(action),
71 callback: callback,
72 };
73 },
74 feature = "web_sys" => ({
75 let callback = Closure::wrap(Box::new(callback) as Box<dyn Fn(JsValue)>);
76 let render_id = utils::window().request_animation_frame(callback.as_ref().unchecked_ref()).unwrap();
77 RenderTaskInner {
78 render_id,
79 callback,
80 }
81 }),
82 };
83 RenderTask(handle)
84 }
85}
86
87impl Task for RenderTask {
88 fn is_active(&self) -> bool {
89 true
90 }
91}
92
93impl Drop for RenderTask {
94 fn drop(&mut self) {
95 if self.is_active() {
96 cfg_match! {
97 feature = "std_web" => ({
98 let handle = &self.0;
99 js! { @(no_return)
100 var handle = @{handle};
101 cancelAnimationFrame(handle.render_id);
102 handle.callback.drop();
103 }
104 }),
105 feature = "web_sys" => utils::window().cancel_animation_frame(self.0.render_id).unwrap(),
106 }
107 }
108 }
109}