Skip to main content

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}