From 03ad7120ab9cbe336564e24e7cdb926d8319ec19 Mon Sep 17 00:00:00 2001 From: mmavka Date: Tue, 14 Apr 2026 22:52:01 +0200 Subject: [PATCH] feat: add public current_viewport() getter + ViewportInfo Adds PlotWidget::current_viewport() returning the current data-space x/y ranges plus the plot-area pixel rectangle as a new public ViewportInfo struct. Reads from the widget's cached camera_bounds state which is already synced on every pan/zoom/resize via the internal RenderUpdate flow. For non-linear axis scales (Log), plot-space values are inverted back to data-space before return. Enables downstream code to coordinate external behavior with the plot viewport (e.g. fetching a data range from a backend, syncing a secondary view, serializing session state) without having to subscribe to PlotUiMessage::RenderUpdate and parse tick positions out of its doc-hidden payload. --- src/lib.rs | 2 +- src/plot_widget.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 114055c..89fd340 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ pub use controls::{PanControls, PickControls, PlotControls, ZoomControls}; pub use fill::Fill; pub use grid::TickWeight; pub use message::{DragEvent, HoverPickEvent, PlotUiMessage, PointId, TooltipContext}; -pub use plot_widget::{HighlightPoint, PlotWidget}; +pub use plot_widget::{HighlightPoint, PlotWidget, ViewportInfo}; pub use plot_widget_builder::PlotWidgetBuilder; pub use point::{MarkerType, Point}; pub use reference_lines::{HLine, VLine}; diff --git a/src/plot_widget.rs b/src/plot_widget.rs index 3305e50..377d507 100644 --- a/src/plot_widget.rs +++ b/src/plot_widget.rs @@ -50,6 +50,24 @@ pub(crate) type CursorProvider = Arc String + Send + Sync>; pub(crate) type HighlightPointProvider = Arc, &mut HighlightPoint) -> Option + Send + Sync>; +/// Current viewport state of a [`PlotWidget`]. +/// +/// Produced by [`PlotWidget::current_viewport`]. Captures the data-space +/// ranges visible along each axis and the pixel rectangle of the plot area. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct ViewportInfo { + /// Left edge of the visible data-space range along the x-axis. + pub x_min: f64, + /// Right edge of the visible data-space range along the x-axis. + pub x_max: f64, + /// Bottom edge of the visible data-space range along the y-axis. + pub y_min: f64, + /// Top edge of the visible data-space range along the y-axis. + pub y_max: f64, + /// Pixel rectangle of the plot-area (excludes axes, labels, legend). + pub plot_area: Rectangle, +} + /// A plot widget that renders data series with interactive features. pub struct PlotWidget { pub(crate) instance_id: u64, @@ -281,6 +299,46 @@ impl PlotWidget { self.y_lim = Some((min, max)); } + /// Read the current data-space viewport and plot-area pixel rectangle. + /// + /// Returns `None` before the first frame has been rendered (the widget + /// populates this lazily from the shader program's update phase). Once + /// available, the returned values track pan/zoom/resize in near real time. + /// + /// Ranges are returned in data-space coordinates: for non-linear axis + /// scales (e.g. `AxisScale::Log`), the internal plot-space values are + /// inverted back to data-space before being returned. + pub fn current_viewport(&self) -> Option { + let (camera, bounds) = self.camera_bounds.as_ref()?; + let x_min_plot = camera.position.x - camera.half_extents.x; + let x_max_plot = camera.position.x + camera.half_extents.x; + let y_min_plot = camera.position.y - camera.half_extents.y; + let y_max_plot = camera.position.y + camera.half_extents.y; + let x_min = self + .x_axis_scale + .plot_to_data(x_min_plot) + .unwrap_or(x_min_plot); + let x_max = self + .x_axis_scale + .plot_to_data(x_max_plot) + .unwrap_or(x_max_plot); + let y_min = self + .y_axis_scale + .plot_to_data(y_min_plot) + .unwrap_or(y_min_plot); + let y_max = self + .y_axis_scale + .plot_to_data(y_max_plot) + .unwrap_or(y_max_plot); + Some(ViewportInfo { + x_min, + x_max, + y_min, + y_max, + plot_area: *bounds, + }) + } + /// Set the y-axis scale mode. /// /// This does not modify tick producer/formatter settings.