Skip to main content

egui_charts/config/
tooltip.rs

1//! Tooltip configuration for data display on hover.
2//!
3//! Provides three tooltip variants:
4//! - **Floating**: Classic tooltip popup that follows the cursor
5//! - **Tracking**: Fixed horizontal bar at the top of the chart showing OHLC data
6//! - **Magnifier**: Circular zoom lens for detailed data inspection on dense charts
7
8use crate::tokens::DESIGN_TOKENS;
9use egui::Color32;
10
11/// Tooltip display mode
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
13pub enum TooltipMode {
14    /// Floating tooltip that follows cursor position
15    /// Shows OHLC, volume, and change info in a popup near the mouse
16    #[default]
17    Floating,
18
19    /// Tracking tooltip - fixed position bar at top of chart
20    /// Shows: O: xxx  H: xxx  L: xxx  C: xxx  Vol: xxx  (+x.xx%)
21    /// Updates as cursor moves horizontally across the chart
22    Tracking,
23
24    /// Magnifier tooltip - circular zoom lens following cursor
25    /// Shows magnified view of candles/data under the cursor
26    /// Useful for detailed analysis on dense charts
27    Magnifier,
28}
29
30impl std::fmt::Display for TooltipMode {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            TooltipMode::Floating => write!(f, "Floating"),
34            TooltipMode::Tracking => write!(f, "Tracking"),
35            TooltipMode::Magnifier => write!(f, "Magnifier"),
36        }
37    }
38}
39
40/// Tooltip configuration options
41#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
42#[non_exhaustive]
43pub struct TooltipOptions {
44    /// Whether the hover readout is drawn at all.
45    ///
46    /// When `false` the chart still shows the crosshair but suppresses the
47    /// OHLC/value readout, matching charting UIs that let users toggle the
48    /// data tooltip independently of the crosshair.
49    pub enabled: bool,
50
51    /// Show values only while the primary pointer is held. Touch waits for a long press.
52    pub on_long_press: bool,
53
54    /// Tooltip display mode
55    pub mode: TooltipMode,
56
57    /// Show OHLC values (Open, High, Low, Close)
58    pub show_ohlc: bool,
59
60    /// Show volume
61    pub show_volume: bool,
62
63    /// Include volume study plot details in held values, in addition to total volume.
64    /// Other study values and hover readouts retain their existing visibility.
65    #[serde(default)]
66    pub show_volume_details: bool,
67
68    /// Show price change (absolute and percentage)
69    pub show_change: bool,
70
71    /// Show ts
72    pub show_time: bool,
73
74    /// Show indicator values (if indicators are present)
75    pub show_indicators: bool,
76
77    /// Magnifier zoom level (2.0 = 2x zoom, 3.0 = 3x zoom), drawn within 0.1 to 100 (NaN as 0.1)
78    /// Only applies when mode is Magnifier
79    pub magnifier_zoom: f32,
80
81    /// Magnifier lens diameter in pixels, drawn no larger than the plot's smaller side
82    /// Only applies when mode is Magnifier
83    pub magnifier_size: f32,
84
85    /// Background color for floating tooltip (`Color32::PLACEHOLDER`: active theme)
86    pub background_color: Color32,
87
88    /// Text color for tooltip content (`Color32::PLACEHOLDER`: active theme)
89    pub text_color: Color32,
90
91    /// Border color for the floating tooltip of a rising bar (`Color32::PLACEHOLDER`: active theme)
92    pub border_color_bullish: Color32,
93
94    /// Border color for the floating tooltip of a falling bar (`Color32::PLACEHOLDER`: active theme)
95    pub border_color_bearish: Color32,
96
97    /// Font size for tooltip text
98    pub font_size: f32,
99
100    /// Most decimals for price values. The floating tooltip shows fewer for prices whose
101    /// magnitude needs fewer; the tracking bar shows this many, at most 4.
102    pub price_precision: usize,
103
104    /// Tracking bar height (for Tracking mode)
105    pub tracking_bar_height: f32,
106
107    /// Tracking bar background color (`Color32::PLACEHOLDER`: active theme)
108    pub tracking_bar_background: Color32,
109}
110
111impl Default for TooltipOptions {
112    fn default() -> Self {
113        Self {
114            enabled: true,
115            on_long_press: false,
116            mode: TooltipMode::Floating,
117            show_ohlc: true,
118            show_volume: true,
119            show_volume_details: false,
120            show_change: true,
121            show_time: true,
122            show_indicators: true,
123            magnifier_zoom: 2.0,
124            magnifier_size: 120.0,
125            background_color: Color32::PLACEHOLDER,
126            text_color: Color32::PLACEHOLDER,
127            border_color_bullish: Color32::PLACEHOLDER,
128            border_color_bearish: Color32::PLACEHOLDER,
129            font_size: 11.0,
130            price_precision: 8,
131            tracking_bar_height: 24.0,
132            tracking_bar_background: Color32::PLACEHOLDER,
133        }
134    }
135}
136
137impl TooltipOptions {
138    /// These options with `Color32::PLACEHOLDER` colours taken from the theme applied to
139    /// `ctx`, or from the dark tokens when none has been applied.
140    pub(crate) fn resolved(&self, ctx: &egui::Context) -> Self {
141        let theme = crate::theme::applied_theme(ctx);
142        let chart = theme.as_ref().map(|theme| theme.chart);
143        let border = theme.map(|theme| theme.ui.border);
144        let tokens = &DESIGN_TOKENS.semantic;
145        let or = |color: Color32, themed: Option<Color32>, fallback: Color32| {
146            if color == Color32::PLACEHOLDER {
147                themed.unwrap_or(fallback)
148            } else {
149                color
150            }
151        };
152        Self {
153            background_color: or(
154                self.background_color,
155                chart.map(|c| c.bg_tooltip),
156                tokens.extended.chart_tooltip_bg,
157            ),
158            text_color: or(
159                self.text_color,
160                chart.map(|c| c.axis_text),
161                tokens.extended.chart_text,
162            ),
163            border_color_bullish: or(self.border_color_bullish, border, tokens.ui.border_dark),
164            border_color_bearish: or(self.border_color_bearish, border, tokens.ui.border_dark),
165            tracking_bar_background: or(
166                self.tracking_bar_background,
167                chart.map(|c| c.bg),
168                tokens.chart.bg,
169            ),
170            ..self.clone()
171        }
172    }
173
174    /// Create tooltip options with floating mode
175    pub fn floating() -> Self {
176        Self {
177            mode: TooltipMode::Floating,
178            ..Default::default()
179        }
180    }
181
182    /// Create tooltip options with tracking mode
183    pub fn tracking() -> Self {
184        Self {
185            mode: TooltipMode::Tracking,
186            ..Default::default()
187        }
188    }
189
190    /// Create tooltip options with magnifier mode
191    pub fn magnifier() -> Self {
192        Self {
193            mode: TooltipMode::Magnifier,
194            ..Default::default()
195        }
196    }
197
198    /// Create magnifier with custom zoom level
199    pub fn magnifier_with_zoom(zoom: f32) -> Self {
200        Self {
201            mode: TooltipMode::Magnifier,
202            magnifier_zoom: zoom,
203            ..Default::default()
204        }
205    }
206
207    /// Set tooltip mode
208    pub fn with_mode(mut self, mode: TooltipMode) -> Self {
209        self.mode = mode;
210        self
211    }
212
213    /// Enable or disable the hover readout.
214    pub fn with_enabled(mut self, enabled: bool) -> Self {
215        self.enabled = enabled;
216        self
217    }
218
219    /// Enable/disable OHLC display
220    pub fn with_ohlc(mut self, show: bool) -> Self {
221        self.show_ohlc = show;
222        self
223    }
224
225    /// Enable/disable volume display
226    pub fn with_volume(mut self, show: bool) -> Self {
227        self.show_volume = show;
228        self
229    }
230
231    /// Enable/disable change display
232    pub fn with_change(mut self, show: bool) -> Self {
233        self.show_change = show;
234        self
235    }
236
237    /// Set magnifier zoom level
238    pub fn with_magnifier_zoom(mut self, zoom: f32) -> Self {
239        self.magnifier_zoom = zoom;
240        self
241    }
242
243    /// Set magnifier size
244    pub fn with_magnifier_size(mut self, size: f32) -> Self {
245        self.magnifier_size = size;
246        self
247    }
248
249    /// Set price precision
250    pub fn with_precision(mut self, precision: usize) -> Self {
251        self.price_precision = precision;
252        self
253    }
254}