egui_charts/widget/pan_zoom/state.rs
1//! Animation and interaction state structs for the `Chart` widget.
2//!
3//! These structs hold ephemeral, per-frame interaction state used by the
4//! [`pan_zoom`](super) module to implement smooth scrolling,
5//! box-zoom selection, and elastic edge bounce effects.
6
7use egui::Pos2;
8use web_time::Instant;
9
10/// Tracks kinetic (momentum-based) scrolling after a flick gesture.
11///
12/// When the user drags and releases quickly (trackpad or touch), the chart
13/// continues to scroll with decaying velocity, providing a natural "flick"
14/// feel. The velocity is measured in pixels per second and decays each frame
15/// using the configurable damping coefficient.
16#[derive(Debug, Clone)]
17pub struct KineticScrollState {
18 /// Current scroll velocity in pixels/second (positive = scrolling right).
19 pub velocity: f32,
20 /// Last pointer position during drag (for velocity calculation).
21 pub last_pos: Option<Pos2>,
22 /// Timestamp of the last pointer sample.
23 pub last_time: Option<Instant>,
24 /// Whether kinetic animation is currently running.
25 pub is_active: bool,
26 /// Last animation frame time (for delta-time calculation).
27 pub anim_last_time: Option<Instant>,
28}
29
30impl Default for KineticScrollState {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl KineticScrollState {
37 /// Create a new idle kinetic scroll state with zero velocity.
38 pub fn new() -> Self {
39 Self {
40 velocity: 0.0,
41 last_pos: None,
42 last_time: None,
43 is_active: false,
44 anim_last_time: None,
45 }
46 }
47}
48
49/// Tracks an active box-zoom selection.
50///
51/// The user initiates box zoom by left-clicking when zoom mode is active,
52/// then drags to define a rectangular region. On release the chart zooms
53/// into the selection.
54#[derive(Debug, Clone)]
55pub struct BoxZoomState {
56 /// Whether box zoom is currently active
57 pub active: bool,
58 /// Start position of box drag
59 pub start_pos: Option<Pos2>,
60 /// Current mouse position during drag
61 pub curr_pos: Option<Pos2>,
62}
63
64impl Default for BoxZoomState {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl BoxZoomState {
71 /// Create a new inactive box-zoom state.
72 pub fn new() -> Self {
73 Self {
74 active: false,
75 start_pos: None,
76 curr_pos: None,
77 }
78 }
79
80 /// Reset the box-zoom to inactive, clearing start and current positions.
81 pub fn reset(&mut self) {
82 self.active = false;
83 self.start_pos = None;
84 self.curr_pos = None;
85 }
86}
87
88/// Tracks elastic bounce-back animation when the user scrolls past chart edges.
89///
90/// When the chart reaches its data boundaries, a spring-like bounce animation
91/// pushes the viewport back into valid range. This prevents the user from
92/// scrolling into empty space and provides tactile feedback.
93#[derive(Debug, Clone)]
94pub struct ElasticBounceState {
95 /// Bounce velocity (pixels per second)
96 pub velocity: f32,
97 /// Whether bounce animation is active
98 pub active: bool,
99 /// Last update time for animation
100 pub last_time: Option<Instant>,
101}
102
103impl Default for ElasticBounceState {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl ElasticBounceState {
110 /// Create a new idle elastic bounce state.
111 pub fn new() -> Self {
112 Self {
113 velocity: 0.0,
114 active: false,
115 last_time: None,
116 }
117 }
118}