1use crate::controller::request_animation_frame;
2use futures::{stream, Stream};
3use interpolation::Lerp;
4use js_sys::Date;
5use std::time::Duration;
6
7pub fn spring<V>(from: V, to: V, duration: Duration) -> impl Stream<Item = V>
9where
10 V: Lerp<Scalar = f32> + Clone + 'static,
11{
12 let mut start_cell = None;
13 stream::unfold(false, move |is_done| {
14 if start_cell.is_none() {
15 start_cell = Some(Date::now());
16 }
17 let start = start_cell.unwrap();
18
19 let from = from.clone();
20 let to = to.clone();
21 async move {
22 if is_done {
23 return None;
24 }
25
26 request_animation_frame().await;
27
28 let dt = Date::now() - start;
29 let duration_ms = duration.as_secs_f64() * 1000.;
30 if dt >= duration_ms {
31 let v = interpolation::lerp(&from, &to, &1.);
32 return Some((v, true));
33 }
34
35 let x = dt / duration_ms;
36 let v = interpolation::lerp(&from, &to, &(x as f32));
37 Some((v, false))
38 }
39 })
40}