Skip to content

feat: add public plot_area_bounds() getter#22

Open
mmavka wants to merge 1 commit intodonkeyteethUX:mainfrom
mmavka:upstream-pr/plot-area-bounds
Open

feat: add public plot_area_bounds() getter#22
mmavka wants to merge 1 commit intodonkeyteethUX:mainfrom
mmavka:upstream-pr/plot-area-bounds

Conversation

@mmavka
Copy link
Copy Markdown

@mmavka mmavka commented Apr 14, 2026

Motivation

Applications embedding PlotWidget sometimes need the current pixel
rectangle of the plot area (excluding axes, labels, legend) but don't need
the data-space ranges. Common cases:

  • Choosing an LOD level when requesting downsampled data from a streaming
    source: the right bucket resolution depends on how many pixels each
    bucket will cover.
  • Laying out overlay UI relative to the plot area (status badges,
    drawing tools, floating annotations placed in world coordinates but
    clipped to the plot box).
  • Computing hit-test regions for custom interaction widgets layered
    on top of the plot via iced::widget::stack!.

Today, the plot area rectangle is cached on PlotWidget as part of
camera_bounds, but that field is crate-private; RenderUpdate also
carries the bounds in its camera_bounds payload, but that payload is
pub(crate) behind a #[doc(hidden)] struct. So even though the data is
already tracked and updated on every pan/zoom/resize, there is no
public way to read it.

This PR exposes the minimum-viable getter for that case: a one-liner
that returns Option<Rectangle>.

What this PR does

  • Adds PlotWidget::plot_area_bounds(&self) -> Option<Rectangle>.
  • Reads from the existing cached camera_bounds state — no new state,
    no new tracking logic.
  • Returns None if the widget hasn't been rendered yet (camera_bounds is
    lazily populated during the first shader update).

API additions

impl PlotWidget {
    /// Pixel rectangle of the plot area (excluding axes, labels, legend).
    /// Returns `None` before the first frame has been rendered.
    #[must_use]
    pub fn plot_area_bounds(&self) -> Option<Rectangle> { /* ... */ }
}

Non-breaking

  • No existing public API is changed.
  • No behavioral changes.
  • 10 insertions, 0 deletions.
  • Single file, single method.

Example use case

use iced::window;
use iced_plot::PlotWidget;

fn choose_lod_bucket(plot: &PlotWidget, visible_x_range: (f64, f64)) -> f64 {
    let (x_min, x_max) = visible_x_range;
    let Some(area) = plot.plot_area_bounds() else {
        return (x_max - x_min) / 100.0; // fallback
    };
    let px = area.width as f64;
    // one data bucket per pixel
    (x_max - x_min) / px.max(1.0)
}

Alternatives considered

  • Returning the rectangle only through the richer current_viewport()
    getter
    (proposed in a separate PR). Viable, but callers that only
    care about pixel dimensions shouldn't have to allocate/cover a full
    ViewportInfo or invert axis scales that they don't use.
  • Returning Option<(f32, f32)> for just width+height. Loses
    absolute position, which overlay UIs need.

Related

None. Complementary to any viewport-exposure PR, but independent —
applications that only need pixel dimensions can use this alone.

Returns Option<Rectangle> with the current pixel rectangle of the
plot area (excluding axes, labels, legend). Reads from the widget's
cached camera_bounds state, which is kept in sync on every
pan/zoom/resize via the internal RenderUpdate flow.

Useful for applications that need the plot area's pixel dimensions
to make pixel-aware decisions (e.g. choosing an LOD level when
requesting downsampled data from a streaming source, or laying out
overlay UI relative to the plot area).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant