Skip to content

Commit 5cdf8a4

Browse files
irudoySomethingNew71
authored andcommitted
fix(ui): apply zoom to view_window in cursor-tracking mode
Pinch and cmd+wheel zoom were silently no-ops while cursor_tracking was on (the default). The cursor-tracking branch in the chart closure forces bounds to a window of view_window_seconds centered on the cursor every frame, overwriting any zoom egui_plot just applied. Translate zoom_delta (and smooth_scroll_delta.y when scroll_to_zoom is enabled) into changes of view_window_seconds itself, so the window shrinks/grows around the cursor as the user expects.
1 parent cb65f93 commit 5cdf8a4

1 file changed

Lines changed: 35 additions & 2 deletions

File tree

src/ui/chart.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ use crate::state::{
1111
MIN_PLOT_HEIGHT, PLOT_RESIZE_HANDLE_HEIGHT,
1212
};
1313

14+
/// Sensitivity multiplier for scroll-to-zoom (higher = faster zoom per scroll tick).
15+
/// Shared between the cursor-tracking pre-show helper and the post-show closure.
16+
const SCROLL_ZOOM_SENSITIVITY: f64 = 0.003;
17+
1418
impl UltraLogApp {
1519
/// Render the main chart with cached downsampled data
1620
pub fn render_chart(&mut self, ui: &mut egui::Ui) {
@@ -27,8 +31,37 @@ impl UltraLogApp {
2731
}
2832
}
2933

34+
/// Translate pinch / cmd+wheel (and scroll if `scroll_to_zoom` is on) into
35+
/// changes of `view_window_seconds` while in cursor-tracking mode. Without
36+
/// this, the cursor-tracking branch in the plot closure forces bounds to a
37+
/// fixed-width window every frame and any zoom is immediately overridden.
38+
fn apply_zoom_to_view_window_if_tracking(&mut self, ui: &egui::Ui) {
39+
if !self.cursor_tracking {
40+
return;
41+
}
42+
let Some((min_t, max_t)) = self.get_time_range() else {
43+
return;
44+
};
45+
let zoom_delta = ui.input(|i| i.zoom_delta()) as f64;
46+
let mut new_window = self.view_window_seconds;
47+
if zoom_delta != 1.0 {
48+
new_window /= zoom_delta;
49+
}
50+
if self.scroll_to_zoom {
51+
let scroll_y = ui.input(|i| i.smooth_scroll_delta.y) as f64;
52+
if scroll_y.abs() > 0.1 {
53+
let factor = (1.0 - scroll_y * SCROLL_ZOOM_SENSITIVITY).clamp(0.8, 1.25);
54+
new_window *= factor;
55+
}
56+
}
57+
let max_window = (max_t - min_t).max(0.1);
58+
self.view_window_seconds = new_window.clamp(0.1, max_window);
59+
}
60+
3061
/// Render single-plot mode chart (original implementation)
3162
fn render_chart_single_mode(&mut self, ui: &mut egui::Ui) {
63+
self.apply_zoom_to_view_window_if_tracking(ui);
64+
3265
// Get selected channels from active tab
3366
let selected_channels = self.get_selected_channels().to_vec();
3467

@@ -129,8 +162,6 @@ impl UltraLogApp {
129162
// Fixed Y bounds for normalized data (0-1 with small padding)
130163
const Y_MIN: f64 = -0.05;
131164
const Y_MAX: f64 = 1.05;
132-
/// Sensitivity multiplier for scroll-to-zoom (higher = faster zoom per scroll tick)
133-
const SCROLL_ZOOM_SENSITIVITY: f64 = 0.003;
134165

135166
// Build the plot - X-axis zoom only, Y fixed
136167
// When scroll_to_zoom is enabled, disable scroll-to-pan so we handle scroll as zoom
@@ -324,6 +355,8 @@ impl UltraLogApp {
324355

325356
/// Render stacked plot areas
326357
fn render_chart_stacked_mode(&mut self, ui: &mut egui::Ui) {
358+
self.apply_zoom_to_view_window_if_tracking(ui);
359+
327360
let Some(tab_idx) = self.active_tab else {
328361
ui.centered_and_justified(|ui| {
329362
ui.label(

0 commit comments

Comments
 (0)