use std::cell::RefCell;
use std::rc::Rc;
use tairitsu_vdom::{DomRect, Platform};
pub struct AnimationContext<P: Platform> {
element: P::Element,
platform: Rc<RefCell<P>>,
bounding_rect: DomRect,
previous_time: f64,
current_time: f64,
delta_time: f64,
mouse_pos: Option<(f64, f64)>,
}
impl<P: Platform> AnimationContext<P> {
pub fn new(platform: Rc<RefCell<P>>, element: P::Element) -> Self {
let bounding_rect = platform.borrow_mut().get_bounding_client_rect(&element);
Self {
element,
platform,
bounding_rect,
previous_time: 0.0,
current_time: 0.0,
delta_time: 16.67, mouse_pos: None,
}
}
pub fn new_with_timing(
platform: Rc<RefCell<P>>,
element: P::Element,
previous_time: f64,
current_time: f64,
) -> Self {
let bounding_rect = platform.borrow_mut().get_bounding_client_rect(&element);
let delta_time = current_time - previous_time;
Self {
element,
platform,
bounding_rect,
previous_time,
current_time,
delta_time: delta_time.max(0.0),
mouse_pos: None,
}
}
pub fn update_timing(&mut self, new_time: f64) {
self.previous_time = self.current_time;
self.current_time = new_time;
self.delta_time = (self.current_time - self.previous_time).max(0.0);
}
pub fn set_mouse_position(&mut self, x: f64, y: f64) {
self.mouse_pos = Some((x, y));
}
pub fn element(&self) -> P::Element {
self.element.clone()
}
pub fn element_width(&self) -> f64 {
self.bounding_rect.width
}
pub fn element_height(&self) -> f64 {
self.bounding_rect.height
}
pub fn client_width(&self) -> f64 {
self.bounding_rect.width
}
pub fn client_height(&self) -> f64 {
self.bounding_rect.height
}
pub fn scroll_width(&self) -> f64 {
self.bounding_rect.width
}
pub fn scroll_height(&self) -> f64 {
self.bounding_rect.height
}
pub fn bounding_rect(&self) -> DomRect {
self.bounding_rect
}
pub fn offset_left(&self) -> f64 {
self.bounding_rect.x
}
pub fn offset_top(&self) -> f64 {
self.bounding_rect.y
}
pub fn viewport_left(&self) -> f64 {
self.bounding_rect.x
}
pub fn viewport_top(&self) -> f64 {
self.bounding_rect.y
}
pub fn viewport_right(&self) -> f64 {
self.bounding_rect.x + self.bounding_rect.width
}
pub fn viewport_bottom(&self) -> f64 {
self.bounding_rect.y + self.bounding_rect.height
}
pub fn mouse_x_viewport(&self) -> f64 {
self.mouse_pos.map(|(x, _)| x).unwrap_or(0.0)
}
pub fn mouse_y_viewport(&self) -> f64 {
self.mouse_pos.map(|(_, y)| y).unwrap_or(0.0)
}
pub fn mouse_x(&self) -> f64 {
self.mouse_x_viewport() - self.viewport_left()
}
pub fn mouse_y(&self) -> f64 {
self.mouse_y_viewport() - self.viewport_top()
}
pub fn mouse_x_percent(&self) -> f64 {
let width = self.element_width();
if width > 0.0 {
(self.mouse_x() / width) * 100.0
} else {
0.0
}
}
pub fn mouse_y_percent(&self) -> f64 {
let height = self.element_height();
if height > 0.0 {
(self.mouse_y() / height) * 100.0
} else {
0.0
}
}
pub fn scroll_x(&self) -> f64 {
0.0
}
pub fn scroll_y(&self) -> f64 {
0.0
}
pub fn document_scroll_x(&self) -> f64 {
0.0
}
pub fn document_scroll_y(&self) -> f64 {
0.0
}
pub fn max_scroll_x(&self) -> f64 {
self.scroll_width() - self.client_width()
}
pub fn max_scroll_y(&self) -> f64 {
self.scroll_height() - self.client_height()
}
pub fn scroll_progress_x(&self) -> f64 {
let max = self.max_scroll_x();
if max > 0.0 {
self.scroll_x() / max
} else {
0.0
}
}
pub fn scroll_progress_y(&self) -> f64 {
let max = self.max_scroll_y();
if max > 0.0 {
self.scroll_y() / max
} else {
0.0
}
}
pub fn window_width(&self) -> f64 {
self.platform.borrow().inner_width() as f64
}
pub fn window_height(&self) -> f64 {
self.platform.borrow().inner_height() as f64
}
pub fn now(&self) -> f64 {
self.current_time
}
pub fn previous_time(&self) -> f64 {
self.previous_time
}
pub fn delta_time(&self) -> f64 {
self.delta_time
}
pub fn delta_seconds(&self) -> f64 {
self.delta_time / 1000.0
}
pub fn fps(&self) -> f64 {
if self.delta_time > 0.0 {
1000.0 / self.delta_time
} else {
60.0
}
}
pub fn distance_from_center(&self) -> f64 {
let center_x = self.element_width() / 2.0;
let center_y = self.element_height() / 2.0;
let dx = self.mouse_x() - center_x;
let dy = self.mouse_y() - center_y;
(dx * dx + dy * dy).sqrt()
}
pub fn angle_from_center(&self) -> f64 {
let center_x = self.element_width() / 2.0;
let center_y = self.element_height() / 2.0;
(self.mouse_y() - center_y).atan2(self.mouse_x() - center_x)
}
pub fn is_mouse_inside(&self) -> f64 {
let x = self.mouse_x();
let y = self.mouse_y();
let width = self.element_width();
let height = self.element_height();
if x >= 0.0 && x <= width && y >= 0.0 && y <= height {
1.0
} else {
0.0
}
}
pub fn refresh_bounding_rect(&mut self) {
self.bounding_rect = self
.platform
.borrow_mut()
.get_bounding_client_rect(&self.element);
}
}
#[deprecated(note = "Use AnimationContext::new with platform instead")]
#[doc(hidden)]
#[derive(Default)]
pub struct AnimationContextLegacy {
_private: (),
}
#[deprecated(note = "Use AnimationContext::new with platform instead")]
#[doc(hidden)]
#[allow(deprecated)]
impl AnimationContextLegacy {
pub fn new() -> Self {
Self::default()
}
}