Skip to main content

fission_charts/
animation.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
4pub enum ChartEasing {
5    Linear,
6    EaseIn,
7    EaseOut,
8    EaseInOut,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12pub enum ChartAnimationKind {
13    None,
14    Grow,
15    Fade,
16    Sweep,
17    Pulse,
18    Morph,
19}
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22pub struct ChartAnimation {
23    pub enabled: bool,
24    pub kind: ChartAnimationKind,
25    pub duration_ms: u64,
26    pub delay_ms: u64,
27    pub stagger_ms: u64,
28    pub easing: ChartEasing,
29    pub reduced_motion_safe: bool,
30    pub repeat: bool,
31}
32
33impl Default for ChartAnimation {
34    fn default() -> Self {
35        Self {
36            enabled: false,
37            kind: ChartAnimationKind::Grow,
38            duration_ms: 450,
39            delay_ms: 0,
40            stagger_ms: 24,
41            easing: ChartEasing::EaseOut,
42            reduced_motion_safe: true,
43            repeat: false,
44        }
45    }
46}
47
48impl ChartAnimation {
49    pub fn disabled() -> Self {
50        Self {
51            enabled: false,
52            kind: ChartAnimationKind::None,
53            ..Self::default()
54        }
55    }
56
57    pub fn enter(kind: ChartAnimationKind) -> Self {
58        Self {
59            enabled: true,
60            kind,
61            ..Self::default()
62        }
63    }
64
65    pub fn duration_ms(mut self, duration_ms: u64) -> Self {
66        self.duration_ms = duration_ms;
67        self
68    }
69
70    pub fn delay_ms(mut self, delay_ms: u64) -> Self {
71        self.delay_ms = delay_ms;
72        self
73    }
74
75    pub fn stagger_ms(mut self, stagger_ms: u64) -> Self {
76        self.stagger_ms = stagger_ms;
77        self
78    }
79
80    pub fn easing(mut self, easing: ChartEasing) -> Self {
81        self.easing = easing;
82        self
83    }
84
85    pub fn reduced_motion_safe(mut self, safe: bool) -> Self {
86        self.reduced_motion_safe = safe;
87        self
88    }
89
90    pub fn repeat(mut self, repeat: bool) -> Self {
91        self.repeat = repeat;
92        self
93    }
94
95    pub fn progress_at(&self, elapsed_ms: u64, item_index: usize) -> f32 {
96        if !self.enabled || self.duration_ms == 0 {
97            return 1.0;
98        }
99        let start = self
100            .delay_ms
101            .saturating_add(self.stagger_ms.saturating_mul(item_index as u64));
102        if elapsed_ms <= start {
103            return 0.0;
104        }
105        let raw = ((elapsed_ms - start) as f32 / self.duration_ms as f32).clamp(0.0, 1.0);
106        match self.easing {
107            ChartEasing::Linear => raw,
108            ChartEasing::EaseIn => raw * raw,
109            ChartEasing::EaseOut => 1.0 - (1.0 - raw) * (1.0 - raw),
110            ChartEasing::EaseInOut => {
111                if raw < 0.5 {
112                    2.0 * raw * raw
113                } else {
114                    1.0 - (-2.0 * raw + 2.0).powi(2) / 2.0
115                }
116            }
117        }
118    }
119}