tween_scroll/
tween_scroll.rs1use virtualizer::{Align, Virtualizer, VirtualizerOptions};
3
4#[derive(Clone, Copy, Debug)]
5struct Tween {
6 from: u64,
7 to: u64,
8 start_ms: u64,
9 duration_ms: u64,
10}
11
12impl Tween {
13 fn new(from: u64, to: u64, start_ms: u64, duration_ms: u64) -> Self {
14 Self {
15 from,
16 to,
17 start_ms,
18 duration_ms: duration_ms.max(1),
19 }
20 }
21
22 fn is_done(&self, now_ms: u64) -> bool {
23 now_ms.saturating_sub(self.start_ms) >= self.duration_ms
24 }
25
26 fn sample(&self, now_ms: u64) -> u64 {
27 let elapsed = now_ms.saturating_sub(self.start_ms);
28 let t = (elapsed as f32 / self.duration_ms as f32).clamp(0.0, 1.0);
29 let eased = smoothstep(t);
30
31 let from = self.from as f32;
32 let to = self.to as f32;
33 let v = from + (to - from) * eased;
34 v.max(0.0) as u64
35 }
36
37 fn retarget(&mut self, now_ms: u64, new_to: u64, duration_ms: u64) {
38 let cur = self.sample(now_ms);
39 *self = Self::new(cur, new_to, now_ms, duration_ms);
40 }
41}
42
43fn smoothstep(t: f32) -> f32 {
44 t * t * (3.0 - 2.0 * t)
45}
46
47fn main() {
48 let mut v = Virtualizer::new(VirtualizerOptions::new(10_000, |_| 1));
50 v.set_viewport_and_scroll_clamped(20, 0);
51
52 let to = v.scroll_to_index_offset(2_000, Align::Center);
53 let mut tween = Tween::new(v.scroll_offset(), to, 0, 240);
54
55 let mut now_ms = 0u64;
56 let mut frame = 0u64;
57
58 loop {
59 now_ms = now_ms.saturating_add(16);
61 frame += 1;
62
63 let off = tween.sample(now_ms);
65 v.apply_scroll_offset_event_clamped(off, now_ms);
66
67 let mut first: Option<usize> = None;
69 let mut last: Option<usize> = None;
70 v.for_each_virtual_item(|it| {
71 first.get_or_insert(it.index);
72 last = Some(it.index);
73 });
74
75 if frame.is_multiple_of(5) {
76 println!(
77 "t={now_ms}ms off={} visible={:?} first={:?} last={:?}",
78 v.scroll_offset(),
79 v.visible_range(),
80 first,
81 last
82 );
83 }
84
85 if (120..120 + 16).contains(&now_ms) {
88 let new_to = v.scroll_to_index_offset(7_500, Align::Start);
89 tween.retarget(now_ms, new_to, 300);
90 }
91
92 if tween.is_done(now_ms) {
93 break;
94 }
95 }
96
97 v.set_is_scrolling(false);
99
100 println!(
101 "done: off={} range={:?}",
102 v.scroll_offset(),
103 v.virtual_range()
104 );
105}