1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-28 07:23:13 -04:00

Plot custom zoom (#2714)

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* If applicable, add a screenshot or gif.
* Unless this is a trivial change, add a line to the relevant
`CHANGELOG.md` under "Unreleased".
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./sh/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review you PR, but my time is limited!
-->

- Added methods to zoom the plot programmatically, to match the
previously added `translate_bounds()`.
- Added an example of how this method can be used to customize the plot
navigation.

Closes #1164.
This commit is contained in:
YgorSouza
2024-01-06 22:34:42 +01:00
committed by GitHub
parent 797406de39
commit 5ed2c0aa90
6 changed files with 201 additions and 4 deletions

View File

@@ -1002,6 +1002,10 @@ impl Plot {
auto_bounds = false.into();
}
BoundsModification::AutoBounds(new_auto_bounds) => auto_bounds = new_auto_bounds,
BoundsModification::Zoom(zoom_factor, center) => {
bounds.zoom(zoom_factor, center);
auto_bounds = false.into();
}
}
}
@@ -1341,6 +1345,7 @@ enum BoundsModification {
Set(PlotBounds),
Translate(Vec2),
AutoBounds(Vec2b),
Zoom(Vec2, PlotPoint),
}
/// Provides methods to interact with a plot while building it. It is the single argument of the closure
@@ -1404,6 +1409,31 @@ impl PlotUi {
&self.response
}
/// Scale the plot bounds around a position in screen coordinates.
///
/// Can be useful for implementing alternative plot navigation methods.
///
/// The plot bounds are divided by `zoom_factor`, therefore:
/// - `zoom_factor < 1.0` zooms out, i.e., increases the visible range to show more data.
/// - `zoom_factor > 1.0` zooms in, i.e., reduces the visible range to show more detail.
pub fn zoom_bounds(&mut self, zoom_factor: Vec2, center: PlotPoint) {
self.bounds_modifications
.push(BoundsModification::Zoom(zoom_factor, center));
}
/// Scale the plot bounds around the hovered position, if any.
///
/// Can be useful for implementing alternative plot navigation methods.
///
/// The plot bounds are divided by `zoom_factor`, therefore:
/// - `zoom_factor < 1.0` zooms out, i.e., increases the visible range to show more data.
/// - `zoom_factor > 1.0` zooms in, i.e., reduces the visible range to show more detail.
pub fn zoom_bounds_around_hovered(&mut self, zoom_factor: Vec2) {
if let Some(hover_pos) = self.pointer_coordinate() {
self.zoom_bounds(zoom_factor, hover_pos);
}
}
/// The pointer position in plot coordinates. Independent of whether the pointer is in the plot area.
pub fn pointer_coordinate(&self) -> Option<PlotPoint> {
// We need to subtract the drag delta to keep in sync with the frame-delayed screen transform:

View File

@@ -150,6 +150,13 @@ impl PlotBounds {
self.translate_y(delta.y as f64);
}
pub(crate) fn zoom(&mut self, zoom_factor: Vec2, center: PlotPoint) {
self.min[0] = center.x + (self.min[0] - center.x) / (zoom_factor.x as f64);
self.max[0] = center.x + (self.max[0] - center.x) / (zoom_factor.x as f64);
self.min[1] = center.y + (self.min[1] - center.y) / (zoom_factor.y as f64);
self.max[1] = center.y + (self.max[1] - center.y) / (zoom_factor.y as f64);
}
pub(crate) fn add_relative_margin_x(&mut self, margin_fraction: Vec2) {
let width = self.width().max(0.0);
self.expand_x(margin_fraction.x as f64 * width);
@@ -255,10 +262,7 @@ impl PlotTransform {
let center = self.value_from_position(center);
let mut new_bounds = self.bounds;
new_bounds.min[0] = center.x + (new_bounds.min[0] - center.x) / (zoom_factor.x as f64);
new_bounds.max[0] = center.x + (new_bounds.max[0] - center.x) / (zoom_factor.x as f64);
new_bounds.min[1] = center.y + (new_bounds.min[1] - center.y) / (zoom_factor.y as f64);
new_bounds.max[1] = center.y + (new_bounds.max[1] - center.y) / (zoom_factor.y as f64);
new_bounds.zoom(zoom_factor, center);
if new_bounds.is_valid() {
self.bounds = new_bounds;