1use eazy_core::Curve;
7use eazy_core::Easing;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum StaggerFrom {
12 #[default]
14 Start,
15 End,
17 Center,
19 Edges,
21 Random,
23}
24
25impl StaggerFrom {
26 pub fn index_factor(&self, index: usize, total: usize) -> f32 {
31 if total <= 1 {
32 return 0.0;
33 }
34
35 let i = index as f32;
36 let n = (total - 1) as f32;
37
38 match self {
39 Self::Start => i / n,
40 Self::End => (n - i) / n,
41 Self::Center => {
42 let center = n / 2.0;
43 let distance = (i - center).abs();
44
45 distance / center
46 }
47 Self::Edges => {
48 let center = n / 2.0;
49 let distance = (i - center).abs();
50
51 1.0 - (distance / center)
52 }
53 Self::Random => {
54 let hash = ((index as u32).wrapping_mul(2654435761)) as f32;
56
57 hash / u32::MAX as f32
58 }
59 }
60 }
61}
62
63#[derive(Debug, Clone, Default)]
80pub struct Stagger {
81 each: f32,
83 from: StaggerFrom,
85 ease: Option<Easing>,
87 total: Option<f32>,
90}
91
92impl Stagger {
93 pub fn each(delay: f32) -> Self {
95 Self {
96 each: delay.max(0.0),
97 from: StaggerFrom::default(),
98 ease: None,
99 total: None,
100 }
101 }
102
103 pub fn total(duration: f32) -> Self {
107 Self {
108 each: 0.0,
109 from: StaggerFrom::default(),
110 ease: None,
111 total: Some(duration.max(0.0)),
112 }
113 }
114
115 pub fn from(mut self, from: StaggerFrom) -> Self {
117 self.from = from;
118 self
119 }
120
121 pub fn ease(mut self, easing: Easing) -> Self {
126 self.ease = Some(easing);
127 self
128 }
129
130 pub fn delay_for(&self, index: usize, total: usize) -> f32 {
141 if total == 0 {
142 return 0.0;
143 }
144
145 if total == 1 {
146 return 0.0;
147 }
148
149 let factor = self.from.index_factor(index, total);
151
152 let eased_factor = match &self.ease {
154 Some(easing) => easing.y(factor),
155 None => factor,
156 };
157
158 let each_delay = match self.total {
160 Some(t) => t / (total - 1) as f32,
161 None => self.each,
162 };
163
164 eased_factor * each_delay * (total - 1) as f32
165 }
166
167 pub fn total_stagger_duration(&self, count: usize) -> f32 {
171 if count <= 1 {
172 return 0.0;
173 }
174
175 match self.total {
176 Some(t) => t,
177 None => self.each * (count - 1) as f32,
178 }
179 }
180
181 pub fn each_delay(&self) -> f32 {
183 self.each
184 }
185
186 pub fn direction(&self) -> StaggerFrom {
188 self.from
189 }
190}
191
192pub fn calculate_stagger_delays(stagger: &Stagger, count: usize) -> Vec<f32> {
196 (0..count).map(|i| stagger.delay_for(i, count)).collect()
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_stagger_each() {
205 let stagger = Stagger::each(0.1);
206
207 assert_eq!(stagger.delay_for(0, 5), 0.0);
208 assert!((stagger.delay_for(1, 5) - 0.1).abs() < 0.001);
209 assert!((stagger.delay_for(2, 5) - 0.2).abs() < 0.001);
210 assert!((stagger.delay_for(4, 5) - 0.4).abs() < 0.001);
211 }
212
213 #[test]
214 fn test_stagger_from_end() {
215 let stagger = Stagger::each(0.1).from(StaggerFrom::End);
216
217 assert!((stagger.delay_for(0, 5) - 0.4).abs() < 0.001);
218 assert!((stagger.delay_for(4, 5) - 0.0).abs() < 0.001);
219 }
220
221 #[test]
222 fn test_stagger_from_center() {
223 let stagger = Stagger::each(0.1).from(StaggerFrom::Center);
224
225 assert!((stagger.delay_for(2, 5) - 0.0).abs() < 0.001);
228 assert!((stagger.delay_for(1, 5) - 0.2).abs() < 0.001);
229 assert!((stagger.delay_for(3, 5) - 0.2).abs() < 0.001);
230 assert!((stagger.delay_for(0, 5) - 0.4).abs() < 0.001);
231 assert!((stagger.delay_for(4, 5) - 0.4).abs() < 0.001);
232 }
233
234 #[test]
235 fn test_stagger_total() {
236 let stagger = Stagger::total(1.0);
237
238 assert_eq!(stagger.delay_for(0, 5), 0.0);
240 assert!((stagger.delay_for(1, 5) - 0.25).abs() < 0.001);
241 assert!((stagger.delay_for(4, 5) - 1.0).abs() < 0.001);
242 }
243
244 #[test]
245 fn test_stagger_single_item() {
246 let stagger = Stagger::each(0.1);
247
248 assert_eq!(stagger.delay_for(0, 1), 0.0);
249 }
250
251 #[test]
252 fn test_stagger_empty() {
253 let stagger = Stagger::each(0.1);
254
255 assert_eq!(stagger.delay_for(0, 0), 0.0);
256 }
257
258 #[test]
259 fn test_total_stagger_duration() {
260 let stagger = Stagger::each(0.1);
261
262 assert_eq!(stagger.total_stagger_duration(5), 0.4);
263 assert_eq!(stagger.total_stagger_duration(1), 0.0);
264 }
265
266 #[test]
267 fn test_calculate_stagger_delays() {
268 let stagger = Stagger::each(0.1);
269 let delays = calculate_stagger_delays(&stagger, 3);
270
271 assert_eq!(delays.len(), 3);
272 assert_eq!(delays[0], 0.0);
273 assert!((delays[1] - 0.1).abs() < 0.001);
274 assert!((delays[2] - 0.2).abs() < 0.001);
275 }
276}