fission_charts/
animation.rs1use 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}