dioxus_html/events/
visible.rs1use std::{
2 fmt::{Display, Formatter},
3 time::SystemTime,
4};
5
6pub struct VisibleData {
7 inner: Box<dyn HasVisibleData>,
8}
9
10impl<E: HasVisibleData> From<E> for VisibleData {
11 fn from(e: E) -> Self {
12 Self { inner: Box::new(e) }
13 }
14}
15
16impl VisibleData {
17 pub fn new(inner: impl HasVisibleData + 'static) -> Self {
19 Self {
20 inner: Box::new(inner),
21 }
22 }
23
24 pub fn get_bounding_client_rect(&self) -> VisibleResult<PixelsRect> {
26 self.inner.get_bounding_client_rect()
27 }
28
29 pub fn get_intersection_ratio(&self) -> VisibleResult<f64> {
31 self.inner.get_intersection_ratio()
32 }
33
34 pub fn get_intersection_rect(&self) -> VisibleResult<PixelsRect> {
36 self.inner.get_intersection_rect()
37 }
38
39 pub fn is_intersecting(&self) -> VisibleResult<bool> {
41 self.inner.is_intersecting()
42 }
43
44 pub fn get_root_bounds(&self) -> VisibleResult<PixelsRect> {
46 self.inner.get_root_bounds()
47 }
48
49 pub fn get_time(&self) -> VisibleResult<SystemTime> {
51 self.inner.get_time()
52 }
53
54 pub fn downcast<T: 'static>(&self) -> Option<&T> {
56 self.inner.as_any().downcast_ref::<T>()
57 }
58}
59
60impl std::fmt::Debug for VisibleData {
61 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("VisibleData")
63 .field(
64 "bounding_client_rect",
65 &self.inner.get_bounding_client_rect(),
66 )
67 .field("intersection_ratio", &self.inner.get_intersection_ratio())
68 .field("intersection_rect", &self.inner.get_intersection_rect())
69 .field("is_intersecting", &self.inner.is_intersecting())
70 .field("root_bounds", &self.inner.get_root_bounds())
71 .field("time", &self.inner.get_time())
72 .finish()
73 }
74}
75
76impl PartialEq for VisibleData {
77 fn eq(&self, _: &Self) -> bool {
78 true
79 }
80}
81
82#[cfg(feature = "serialize")]
83#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
84pub struct DOMRect {
85 bottom: f64, height: f64, left: f64, right: f64, top: f64, width: f64, x: f64, y: f64, }
94
95#[cfg(feature = "serialize")]
96impl From<PixelsRect> for DOMRect {
97 fn from(rect: PixelsRect) -> Self {
98 let x = rect.origin.x;
99 let y = rect.origin.y;
100 let height = rect.height();
101 let width = rect.width();
102
103 Self {
104 bottom: y + height,
105 height,
106 left: x,
107 right: x + width,
108 top: y,
109 width,
110 x,
111 y,
112 }
113 }
114}
115
116#[cfg(feature = "serialize")]
117impl From<&DOMRect> for PixelsRect {
118 fn from(rect: &DOMRect) -> Self {
119 PixelsRect::new(
120 euclid::Point2D::new(rect.x, rect.y),
121 euclid::Size2D::new(rect.width, rect.height),
122 )
123 }
124}
125
126#[cfg(feature = "serialize")]
127#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
129pub struct SerializedVisibleData {
130 pub bounding_client_rect: DOMRect,
131 pub intersection_ratio: f64,
132 pub intersection_rect: DOMRect,
133 pub is_intersecting: bool,
134 pub root_bounds: DOMRect,
135 pub time_ms: u128,
136}
137
138#[cfg(feature = "serialize")]
139impl SerializedVisibleData {
140 pub fn new(
142 bounding_client_rect: DOMRect,
143 intersection_ratio: f64,
144 intersection_rect: DOMRect,
145 is_intersecting: bool,
146 root_bounds: DOMRect,
147 time_ms: u128,
148 ) -> Self {
149 Self {
150 bounding_client_rect,
151 intersection_ratio,
152 intersection_rect,
153 is_intersecting,
154 root_bounds,
155 time_ms,
156 }
157 }
158}
159
160#[cfg(feature = "serialize")]
161impl From<&VisibleData> for SerializedVisibleData {
162 fn from(data: &VisibleData) -> Self {
163 Self::new(
164 data.get_bounding_client_rect().unwrap().into(),
165 data.get_intersection_ratio().unwrap(),
166 data.get_intersection_rect().unwrap().into(),
167 data.is_intersecting().unwrap(),
168 data.get_root_bounds().unwrap().into(),
169 data.get_time().unwrap().elapsed().unwrap().as_millis(),
170 )
171 }
172}
173
174#[cfg(feature = "serialize")]
175impl HasVisibleData for SerializedVisibleData {
176 fn get_bounding_client_rect(&self) -> VisibleResult<PixelsRect> {
178 Ok((&self.bounding_client_rect).into())
179 }
180
181 fn get_intersection_ratio(&self) -> VisibleResult<f64> {
183 Ok(self.intersection_ratio)
184 }
185
186 fn get_intersection_rect(&self) -> VisibleResult<PixelsRect> {
188 Ok((&self.intersection_rect).into())
189 }
190
191 fn is_intersecting(&self) -> VisibleResult<bool> {
193 Ok(self.is_intersecting)
194 }
195
196 fn get_root_bounds(&self) -> VisibleResult<PixelsRect> {
198 Ok((&self.root_bounds).into())
199 }
200
201 fn get_time(&self) -> VisibleResult<SystemTime> {
203 Ok(SystemTime::UNIX_EPOCH + std::time::Duration::from_millis(self.time_ms as u64))
204 }
205
206 fn as_any(&self) -> &dyn std::any::Any {
207 self
208 }
209}
210
211#[cfg(feature = "serialize")]
212impl serde::Serialize for VisibleData {
213 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
214 SerializedVisibleData::from(self).serialize(serializer)
215 }
216}
217
218#[cfg(feature = "serialize")]
219impl<'de> serde::Deserialize<'de> for VisibleData {
220 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
221 let data = SerializedVisibleData::deserialize(deserializer)?;
222 Ok(Self {
223 inner: Box::new(data),
224 })
225 }
226}
227
228pub trait HasVisibleData: std::any::Any {
229 fn get_bounding_client_rect(&self) -> VisibleResult<PixelsRect> {
231 Err(VisibleError::NotSupported)
232 }
233
234 fn get_intersection_ratio(&self) -> VisibleResult<f64> {
236 Err(VisibleError::NotSupported)
237 }
238
239 fn get_intersection_rect(&self) -> VisibleResult<PixelsRect> {
241 Err(VisibleError::NotSupported)
242 }
243
244 fn is_intersecting(&self) -> VisibleResult<bool> {
246 Err(VisibleError::NotSupported)
247 }
248
249 fn get_root_bounds(&self) -> VisibleResult<PixelsRect> {
251 Err(VisibleError::NotSupported)
252 }
253
254 fn get_time(&self) -> VisibleResult<SystemTime> {
256 Err(VisibleError::NotSupported)
257 }
258
259 fn as_any(&self) -> &dyn std::any::Any;
261}
262
263use dioxus_core::Event;
264
265use crate::geometry::PixelsRect;
266
267pub type VisibleEvent = Event<VisibleData>;
268
269impl_event! {
270 VisibleData;
271
272 onvisible
274}
275
276pub type VisibleResult<T> = Result<T, VisibleError>;
278
279#[derive(Debug)]
280#[non_exhaustive]
282pub enum VisibleError {
283 NotSupported,
285 OperationFailed(Box<dyn std::error::Error>),
287 NoElementId,
289}
290
291impl Display for VisibleError {
292 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
293 match self {
294 VisibleError::NotSupported => {
295 write!(f, "The renderer does not support the requested operation")
296 }
297 VisibleError::OperationFailed(e) => {
298 write!(f, "The operation failed: {}", e)
299 }
300 VisibleError::NoElementId => {
301 write!(f, "The target had no associated ElementId")
302 }
303 }
304 }
305}
306
307impl std::error::Error for VisibleError {}