freya_hooks/use_canvas.rs
1use std::sync::{
2 Arc,
3 Mutex,
4};
5
6use dioxus_core::AttributeValue;
7use dioxus_hooks::{
8 use_memo,
9 use_reactive,
10 Dependency,
11};
12use dioxus_signals::{
13 Memo,
14 Readable,
15};
16use freya_core::custom_attributes::{
17 CanvasReference,
18 CanvasRunner,
19 CanvasRunnerContext,
20 CustomAttributeValues,
21};
22
23/// Holds a rendering hook callback that allows to render to the Canvas.
24#[derive(PartialEq, Clone)]
25pub struct UseCanvas {
26 runner: Memo<UseCanvasRunner>,
27}
28
29#[derive(Clone)]
30pub struct UseCanvasRunner(pub Arc<Mutex<CanvasRunner>>);
31
32impl PartialEq for UseCanvasRunner {
33 fn eq(&self, other: &Self) -> bool {
34 Arc::ptr_eq(&self.0, &other.0)
35 }
36}
37
38impl UseCanvas {
39 pub fn attribute(&self) -> AttributeValue {
40 AttributeValue::any_value(CustomAttributeValues::Canvas(CanvasReference {
41 runner: self.runner.read().0.clone(),
42 }))
43 }
44}
45
46/// Register a rendering hook to gain access to the Canvas.
47/// Reactivity managed through signals.
48///
49/// ## Usage
50/// ```rust,no_run
51/// # use freya::prelude::*;
52/// fn app() -> Element {
53/// let (reference, size) = use_node_signal();
54/// let mut value = use_signal(|| 0);
55/// let platform = use_platform();
56///
57/// let canvas = use_canvas(move || {
58/// let curr = value();
59/// platform.invalidate_drawing_area(size.peek().area);
60/// platform.request_animation_frame();
61/// move |ctx| {
62/// // Draw using the canvas !
63/// // use `curr`
64/// }
65/// });
66///
67/// rsx!(rect {
68/// onclick: move |_| {
69/// value += 1;
70/// },
71/// canvas_reference: canvas.attribute(),
72/// reference,
73/// width: "fill",
74/// height: "fill",
75/// })
76/// }
77/// ```
78pub fn use_canvas<T: FnMut(&mut CanvasRunnerContext) + Sync + Send + 'static>(
79 mut renderer_cb: impl FnMut() -> T + 'static,
80) -> UseCanvas {
81 let runner = use_memo(move || UseCanvasRunner(Arc::new(Mutex::new(renderer_cb()))));
82
83 UseCanvas { runner }
84}
85
86/// Register a rendering hook to gain access to the Canvas.
87/// Reactivity managed with manual dependencies.
88///
89/// ## Usage
90/// ```rust,no_run
91/// # use freya::prelude::*;
92/// fn app() -> Element {
93/// let (reference, size) = use_node_signal();
94/// let mut value = use_signal(|| 0);
95/// let platform = use_platform();
96///
97/// let canvas = use_canvas_with_deps(&value(), move |curr| {
98/// platform.invalidate_drawing_area(size.peek().area);
99/// platform.request_animation_frame();
100/// move |ctx| {
101/// // Draw using the canvas !
102/// // use `curr`
103/// }
104/// });
105///
106/// rsx!(rect {
107/// onclick: move |_| {
108/// value += 1;
109/// },
110/// canvas_reference: canvas.attribute(),
111/// reference,
112/// width: "fill",
113/// height: "fill",
114/// })
115/// }
116/// ```
117pub fn use_canvas_with_deps<
118 D: Dependency,
119 T: FnMut(&mut CanvasRunnerContext) + Sync + Send + 'static,
120>(
121 dependencies: D,
122 mut renderer_cb: impl FnMut(D::Out) -> T + 'static,
123) -> UseCanvas
124where
125 D::Out: 'static,
126{
127 let runner = use_memo(use_reactive(dependencies, move |dependencies| {
128 UseCanvasRunner(Arc::new(Mutex::new(renderer_cb(dependencies))))
129 }));
130
131 UseCanvas { runner }
132}