Return plot transforms (#2935)
* Expose the plot transform to users * Rename plot::ScreenTransform to PlotTransform * Plot: return a PlotResponse with a transform member
This commit is contained in:
parent
ce761e548f
commit
d46cf067ea
|
|
@ -2,7 +2,7 @@ use crate::emath::NumExt;
|
||||||
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
|
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
|
||||||
|
|
||||||
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
|
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
|
||||||
use crate::plot::{BarChart, Cursor, PlotPoint, ScreenTransform};
|
use crate::plot::{BarChart, Cursor, PlotPoint, PlotTransform};
|
||||||
|
|
||||||
/// One bar in a [`BarChart`]. Potentially floating, allowing stacked bar charts.
|
/// One bar in a [`BarChart`]. Potentially floating, allowing stacked bar charts.
|
||||||
/// Width can be changed to allow variable-width histograms.
|
/// Width can be changed to allow variable-width histograms.
|
||||||
|
|
@ -116,7 +116,7 @@ impl Bar {
|
||||||
|
|
||||||
pub(super) fn add_shapes(
|
pub(super) fn add_shapes(
|
||||||
&self,
|
&self,
|
||||||
transform: &ScreenTransform,
|
transform: &PlotTransform,
|
||||||
highlighted: bool,
|
highlighted: bool,
|
||||||
shapes: &mut Vec<Shape>,
|
shapes: &mut Vec<Shape>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -183,7 +183,7 @@ impl RectElement for Bar {
|
||||||
self.orientation
|
self.orientation
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_values_format(&self, transform: &ScreenTransform) -> String {
|
fn default_values_format(&self, transform: &PlotTransform) -> String {
|
||||||
let scale = transform.dvalue_dpos();
|
let scale = transform.dvalue_dpos();
|
||||||
let scale = match self.orientation {
|
let scale = match self.orientation {
|
||||||
Orientation::Horizontal => scale[0],
|
Orientation::Horizontal => scale[0],
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::emath::NumExt;
|
||||||
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
|
use crate::epaint::{Color32, RectShape, Rounding, Shape, Stroke};
|
||||||
|
|
||||||
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
|
use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
|
||||||
use crate::plot::{BoxPlot, Cursor, PlotPoint, ScreenTransform};
|
use crate::plot::{BoxPlot, Cursor, PlotPoint, PlotTransform};
|
||||||
|
|
||||||
/// Contains the values of a single box in a box plot.
|
/// Contains the values of a single box in a box plot.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
@ -136,7 +136,7 @@ impl BoxElem {
|
||||||
|
|
||||||
pub(super) fn add_shapes(
|
pub(super) fn add_shapes(
|
||||||
&self,
|
&self,
|
||||||
transform: &ScreenTransform,
|
transform: &PlotTransform,
|
||||||
highlighted: bool,
|
highlighted: bool,
|
||||||
shapes: &mut Vec<Shape>,
|
shapes: &mut Vec<Shape>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -267,7 +267,7 @@ impl RectElement for BoxElem {
|
||||||
self.point_at(self.argument, self.spread.upper_whisker)
|
self.point_at(self.argument, self.spread.upper_whisker)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_values_format(&self, transform: &ScreenTransform) -> String {
|
fn default_values_format(&self, transform: &PlotTransform) -> String {
|
||||||
let scale = transform.dvalue_dpos();
|
let scale = transform.dvalue_dpos();
|
||||||
let scale = match self.orientation {
|
let scale = match self.orientation {
|
||||||
Orientation::Horizontal => scale[0],
|
Orientation::Horizontal => scale[0],
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use epaint::Mesh;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
use super::{Cursor, LabelFormatter, PlotBounds, ScreenTransform};
|
use super::{Cursor, LabelFormatter, PlotBounds, PlotTransform};
|
||||||
use rect_elem::*;
|
use rect_elem::*;
|
||||||
use values::{ClosestElem, PlotGeometry};
|
use values::{ClosestElem, PlotGeometry};
|
||||||
|
|
||||||
|
|
@ -25,14 +25,14 @@ const DEFAULT_FILL_ALPHA: f32 = 0.05;
|
||||||
/// Container to pass-through several parameters related to plot visualization
|
/// Container to pass-through several parameters related to plot visualization
|
||||||
pub(super) struct PlotConfig<'a> {
|
pub(super) struct PlotConfig<'a> {
|
||||||
pub ui: &'a Ui,
|
pub ui: &'a Ui,
|
||||||
pub transform: &'a ScreenTransform,
|
pub transform: &'a PlotTransform,
|
||||||
pub show_x: bool,
|
pub show_x: bool,
|
||||||
pub show_y: bool,
|
pub show_y: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait shared by things that can be drawn in the plot.
|
/// Trait shared by things that can be drawn in the plot.
|
||||||
pub(super) trait PlotItem {
|
pub(super) trait PlotItem {
|
||||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>);
|
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>);
|
||||||
|
|
||||||
/// For plot-items which are generated based on x values (plotting functions).
|
/// For plot-items which are generated based on x values (plotting functions).
|
||||||
fn initialize(&mut self, x_range: RangeInclusive<f64>);
|
fn initialize(&mut self, x_range: RangeInclusive<f64>);
|
||||||
|
|
@ -49,7 +49,7 @@ pub(super) trait PlotItem {
|
||||||
|
|
||||||
fn bounds(&self) -> PlotBounds;
|
fn bounds(&self) -> PlotBounds;
|
||||||
|
|
||||||
fn find_closest(&self, point: Pos2, transform: &ScreenTransform) -> Option<ClosestElem> {
|
fn find_closest(&self, point: Pos2, transform: &PlotTransform) -> Option<ClosestElem> {
|
||||||
match self.geometry() {
|
match self.geometry() {
|
||||||
PlotGeometry::None => None,
|
PlotGeometry::None => None,
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ impl HLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for HLine {
|
impl PlotItem for HLine {
|
||||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let HLine {
|
let HLine {
|
||||||
y,
|
y,
|
||||||
stroke,
|
stroke,
|
||||||
|
|
@ -293,7 +293,7 @@ impl VLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for VLine {
|
impl PlotItem for VLine {
|
||||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let VLine {
|
let VLine {
|
||||||
x,
|
x,
|
||||||
stroke,
|
stroke,
|
||||||
|
|
@ -423,7 +423,7 @@ fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option<f32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for Line {
|
impl PlotItem for Line {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let Self {
|
let Self {
|
||||||
series,
|
series,
|
||||||
stroke,
|
stroke,
|
||||||
|
|
@ -584,7 +584,7 @@ impl Polygon {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for Polygon {
|
impl PlotItem for Polygon {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let Self {
|
let Self {
|
||||||
series,
|
series,
|
||||||
stroke,
|
stroke,
|
||||||
|
|
@ -696,7 +696,7 @@ impl Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for Text {
|
impl PlotItem for Text {
|
||||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let color = if self.color == Color32::TRANSPARENT {
|
let color = if self.color == Color32::TRANSPARENT {
|
||||||
ui.style().visuals.text_color()
|
ui.style().visuals.text_color()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -836,7 +836,7 @@ impl Points {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for Points {
|
impl PlotItem for Points {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let sqrt_3 = 3_f32.sqrt();
|
let sqrt_3 = 3_f32.sqrt();
|
||||||
let frac_sqrt_3_2 = 3_f32.sqrt() / 2.0;
|
let frac_sqrt_3_2 = 3_f32.sqrt() / 2.0;
|
||||||
let frac_1_sqrt_2 = 1.0 / 2_f32.sqrt();
|
let frac_1_sqrt_2 = 1.0 / 2_f32.sqrt();
|
||||||
|
|
@ -1039,7 +1039,7 @@ impl Arrows {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for Arrows {
|
impl PlotItem for Arrows {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
use crate::emath::*;
|
use crate::emath::*;
|
||||||
let Self {
|
let Self {
|
||||||
origins,
|
origins,
|
||||||
|
|
@ -1178,7 +1178,7 @@ impl PlotImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for PlotImage {
|
impl PlotItem for PlotImage {
|
||||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
let Self {
|
let Self {
|
||||||
position,
|
position,
|
||||||
texture_id,
|
texture_id,
|
||||||
|
|
@ -1369,7 +1369,7 @@ impl BarChart {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for BarChart {
|
impl PlotItem for BarChart {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
for b in &self.bars {
|
for b in &self.bars {
|
||||||
b.add_shapes(transform, self.highlight, shapes);
|
b.add_shapes(transform, self.highlight, shapes);
|
||||||
}
|
}
|
||||||
|
|
@ -1407,7 +1407,7 @@ impl PlotItem for BarChart {
|
||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_closest(&self, point: Pos2, transform: &ScreenTransform) -> Option<ClosestElem> {
|
fn find_closest(&self, point: Pos2, transform: &PlotTransform) -> Option<ClosestElem> {
|
||||||
find_closest_rect(&self.bars, point, transform)
|
find_closest_rect(&self.bars, point, transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1512,7 +1512,7 @@ impl BoxPlot {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlotItem for BoxPlot {
|
impl PlotItem for BoxPlot {
|
||||||
fn shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>) {
|
fn shapes(&self, _ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
|
||||||
for b in &self.boxes {
|
for b in &self.boxes {
|
||||||
b.add_shapes(transform, self.highlight, shapes);
|
b.add_shapes(transform, self.highlight, shapes);
|
||||||
}
|
}
|
||||||
|
|
@ -1550,7 +1550,7 @@ impl PlotItem for BoxPlot {
|
||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_closest(&self, point: Pos2, transform: &ScreenTransform) -> Option<ClosestElem> {
|
fn find_closest(&self, point: Pos2, transform: &PlotTransform) -> Option<ClosestElem> {
|
||||||
find_closest_rect(&self.boxes, point, transform)
|
find_closest_rect(&self.boxes, point, transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1582,7 +1582,7 @@ pub(crate) fn rulers_color(ui: &Ui) -> Color32 {
|
||||||
|
|
||||||
pub(crate) fn vertical_line(
|
pub(crate) fn vertical_line(
|
||||||
pointer: Pos2,
|
pointer: Pos2,
|
||||||
transform: &ScreenTransform,
|
transform: &PlotTransform,
|
||||||
line_color: Color32,
|
line_color: Color32,
|
||||||
) -> Shape {
|
) -> Shape {
|
||||||
let frame = transform.frame();
|
let frame = transform.frame();
|
||||||
|
|
@ -1597,7 +1597,7 @@ pub(crate) fn vertical_line(
|
||||||
|
|
||||||
pub(crate) fn horizontal_line(
|
pub(crate) fn horizontal_line(
|
||||||
pointer: Pos2,
|
pointer: Pos2,
|
||||||
transform: &ScreenTransform,
|
transform: &PlotTransform,
|
||||||
line_color: Color32,
|
line_color: Color32,
|
||||||
) -> Shape {
|
) -> Shape {
|
||||||
let frame = transform.frame();
|
let frame = transform.frame();
|
||||||
|
|
@ -1731,7 +1731,7 @@ pub(super) fn rulers_at_value(
|
||||||
fn find_closest_rect<'a, T>(
|
fn find_closest_rect<'a, T>(
|
||||||
rects: impl IntoIterator<Item = &'a T>,
|
rects: impl IntoIterator<Item = &'a T>,
|
||||||
point: Pos2,
|
point: Pos2,
|
||||||
transform: &ScreenTransform,
|
transform: &PlotTransform,
|
||||||
) -> Option<ClosestElem>
|
) -> Option<ClosestElem>
|
||||||
where
|
where
|
||||||
T: 'a + RectElement,
|
T: 'a + RectElement,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{Orientation, PlotPoint};
|
use super::{Orientation, PlotPoint};
|
||||||
use crate::plot::transform::{PlotBounds, ScreenTransform};
|
use crate::plot::transform::{PlotBounds, PlotTransform};
|
||||||
use epaint::emath::NumExt;
|
use epaint::emath::NumExt;
|
||||||
use epaint::{Color32, Rgba, Stroke};
|
use epaint::{Color32, Rgba, Stroke};
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ pub(super) trait RectElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Debug formatting for hovered-over value, if none is specified by the user
|
/// Debug formatting for hovered-over value, if none is specified by the user
|
||||||
fn default_values_format(&self, transform: &ScreenTransform) -> String;
|
fn default_values_format(&self, transform: &PlotTransform) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,13 @@ use epaint::Hsva;
|
||||||
|
|
||||||
use items::PlotItem;
|
use items::PlotItem;
|
||||||
use legend::LegendWidget;
|
use legend::LegendWidget;
|
||||||
use transform::ScreenTransform;
|
|
||||||
|
|
||||||
pub use items::{
|
pub use items::{
|
||||||
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, HLine, Line, LineStyle, MarkerShape,
|
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, HLine, Line, LineStyle, MarkerShape,
|
||||||
Orientation, PlotImage, PlotPoint, PlotPoints, Points, Polygon, Text, VLine,
|
Orientation, PlotImage, PlotPoint, PlotPoints, Points, Polygon, Text, VLine,
|
||||||
};
|
};
|
||||||
pub use legend::{Corner, Legend};
|
pub use legend::{Corner, Legend};
|
||||||
pub use transform::PlotBounds;
|
pub use transform::{PlotBounds, PlotTransform};
|
||||||
|
|
||||||
use self::items::{horizontal_line, rulers_color, vertical_line};
|
use self::items::{horizontal_line, rulers_color, vertical_line};
|
||||||
|
|
||||||
|
|
@ -104,7 +103,7 @@ struct PlotMemory {
|
||||||
bounds_modified: AxisBools,
|
bounds_modified: AxisBools,
|
||||||
hovered_entry: Option<String>,
|
hovered_entry: Option<String>,
|
||||||
hidden_items: ahash::HashSet<String>,
|
hidden_items: ahash::HashSet<String>,
|
||||||
last_screen_transform: ScreenTransform,
|
last_plot_transform: PlotTransform,
|
||||||
/// Allows to remember the first click position when performing a boxed zoom
|
/// Allows to remember the first click position when performing a boxed zoom
|
||||||
last_click_pos_for_zoom: Option<Pos2>,
|
last_click_pos_for_zoom: Option<Pos2>,
|
||||||
}
|
}
|
||||||
|
|
@ -149,6 +148,20 @@ struct BoundsLinkGroups(HashMap<Id, LinkedBounds>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// What [`Plot::show`] returns.
|
||||||
|
pub struct PlotResponse<R> {
|
||||||
|
/// What the user closure returned.
|
||||||
|
pub inner: R,
|
||||||
|
|
||||||
|
/// The response of the plot.
|
||||||
|
pub response: Response,
|
||||||
|
|
||||||
|
/// The transform between screen coordinates and plot coordinates.
|
||||||
|
pub transform: PlotTransform,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A 2D plot, e.g. a graph of a function.
|
/// A 2D plot, e.g. a graph of a function.
|
||||||
///
|
///
|
||||||
/// [`Plot`] supports multiple lines and points.
|
/// [`Plot`] supports multiple lines and points.
|
||||||
|
|
@ -571,7 +584,7 @@ impl Plot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interact with and add items to the plot and finally draw it.
|
/// Interact with and add items to the plot and finally draw it.
|
||||||
pub fn show<R>(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi) -> R) -> InnerResponse<R> {
|
pub fn show<R>(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi) -> R) -> PlotResponse<R> {
|
||||||
self.show_dyn(ui, Box::new(build_fn))
|
self.show_dyn(ui, Box::new(build_fn))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -579,7 +592,7 @@ impl Plot {
|
||||||
self,
|
self,
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
build_fn: Box<dyn FnOnce(&mut PlotUi) -> R + 'a>,
|
build_fn: Box<dyn FnOnce(&mut PlotUi) -> R + 'a>,
|
||||||
) -> InnerResponse<R> {
|
) -> PlotResponse<R> {
|
||||||
let Self {
|
let Self {
|
||||||
id_source,
|
id_source,
|
||||||
center_x_axis,
|
center_x_axis,
|
||||||
|
|
@ -661,7 +674,7 @@ impl Plot {
|
||||||
bounds_modified: false.into(),
|
bounds_modified: false.into(),
|
||||||
hovered_entry: None,
|
hovered_entry: None,
|
||||||
hidden_items: Default::default(),
|
hidden_items: Default::default(),
|
||||||
last_screen_transform: ScreenTransform::new(
|
last_plot_transform: PlotTransform::new(
|
||||||
rect,
|
rect,
|
||||||
min_auto_bounds,
|
min_auto_bounds,
|
||||||
center_x_axis,
|
center_x_axis,
|
||||||
|
|
@ -674,7 +687,7 @@ impl Plot {
|
||||||
mut bounds_modified,
|
mut bounds_modified,
|
||||||
mut hovered_entry,
|
mut hovered_entry,
|
||||||
mut hidden_items,
|
mut hidden_items,
|
||||||
last_screen_transform,
|
last_plot_transform,
|
||||||
mut last_click_pos_for_zoom,
|
mut last_click_pos_for_zoom,
|
||||||
} = memory;
|
} = memory;
|
||||||
|
|
||||||
|
|
@ -682,7 +695,7 @@ impl Plot {
|
||||||
let mut plot_ui = PlotUi {
|
let mut plot_ui = PlotUi {
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
next_auto_color_idx: 0,
|
next_auto_color_idx: 0,
|
||||||
last_screen_transform,
|
last_plot_transform,
|
||||||
response,
|
response,
|
||||||
bounds_modifications: Vec::new(),
|
bounds_modifications: Vec::new(),
|
||||||
ctx: ui.ctx().clone(),
|
ctx: ui.ctx().clone(),
|
||||||
|
|
@ -691,7 +704,7 @@ impl Plot {
|
||||||
let PlotUi {
|
let PlotUi {
|
||||||
mut items,
|
mut items,
|
||||||
mut response,
|
mut response,
|
||||||
last_screen_transform,
|
last_plot_transform,
|
||||||
bounds_modifications,
|
bounds_modifications,
|
||||||
..
|
..
|
||||||
} = plot_ui;
|
} = plot_ui;
|
||||||
|
|
@ -727,7 +740,7 @@ impl Plot {
|
||||||
items.sort_by_key(|item| item.highlighted());
|
items.sort_by_key(|item| item.highlighted());
|
||||||
|
|
||||||
// --- Bound computation ---
|
// --- Bound computation ---
|
||||||
let mut bounds = *last_screen_transform.bounds();
|
let mut bounds = *last_plot_transform.bounds();
|
||||||
|
|
||||||
// Find the cursors from other plots we need to draw
|
// Find the cursors from other plots we need to draw
|
||||||
let draw_cursors: Vec<Cursor> = if let Some((id, _)) = linked_cursors.as_ref() {
|
let draw_cursors: Vec<Cursor> = if let Some((id, _)) = linked_cursors.as_ref() {
|
||||||
|
|
@ -826,7 +839,7 @@ impl Plot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut transform = ScreenTransform::new(rect, bounds, center_x_axis, center_y_axis);
|
let mut transform = PlotTransform::new(rect, bounds, center_x_axis, center_y_axis);
|
||||||
|
|
||||||
// Enforce aspect ratio
|
// Enforce aspect ratio
|
||||||
if let Some(data_aspect) = data_aspect {
|
if let Some(data_aspect) = data_aspect {
|
||||||
|
|
@ -947,7 +960,7 @@ impl Plot {
|
||||||
coordinates_formatter,
|
coordinates_formatter,
|
||||||
axis_formatters,
|
axis_formatters,
|
||||||
show_axes,
|
show_axes,
|
||||||
transform: transform.clone(),
|
transform,
|
||||||
draw_cursor_x: linked_cursors.as_ref().map_or(false, |(_, group)| group.x),
|
draw_cursor_x: linked_cursors.as_ref().map_or(false, |(_, group)| group.x),
|
||||||
draw_cursor_y: linked_cursors.as_ref().map_or(false, |(_, group)| group.y),
|
draw_cursor_y: linked_cursors.as_ref().map_or(false, |(_, group)| group.y),
|
||||||
draw_cursors,
|
draw_cursors,
|
||||||
|
|
@ -999,7 +1012,7 @@ impl Plot {
|
||||||
bounds_modified,
|
bounds_modified,
|
||||||
hovered_entry,
|
hovered_entry,
|
||||||
hidden_items,
|
hidden_items,
|
||||||
last_screen_transform: transform,
|
last_plot_transform: transform,
|
||||||
last_click_pos_for_zoom,
|
last_click_pos_for_zoom,
|
||||||
};
|
};
|
||||||
memory.store(ui.ctx(), plot_id);
|
memory.store(ui.ctx(), plot_id);
|
||||||
|
|
@ -1010,7 +1023,11 @@ impl Plot {
|
||||||
response
|
response
|
||||||
};
|
};
|
||||||
|
|
||||||
InnerResponse { inner, response }
|
PlotResponse {
|
||||||
|
inner,
|
||||||
|
response,
|
||||||
|
transform,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1026,7 +1043,7 @@ enum BoundsModification {
|
||||||
pub struct PlotUi {
|
pub struct PlotUi {
|
||||||
items: Vec<Box<dyn PlotItem>>,
|
items: Vec<Box<dyn PlotItem>>,
|
||||||
next_auto_color_idx: usize,
|
next_auto_color_idx: usize,
|
||||||
last_screen_transform: ScreenTransform,
|
last_plot_transform: PlotTransform,
|
||||||
response: Response,
|
response: Response,
|
||||||
bounds_modifications: Vec<BoundsModification>,
|
bounds_modifications: Vec<BoundsModification>,
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
|
@ -1049,7 +1066,7 @@ impl PlotUi {
|
||||||
/// further specified in the plot builder, this will return bounds centered on the origin. The bounds do
|
/// further specified in the plot builder, this will return bounds centered on the origin. The bounds do
|
||||||
/// not change until the plot is drawn.
|
/// not change until the plot is drawn.
|
||||||
pub fn plot_bounds(&self) -> PlotBounds {
|
pub fn plot_bounds(&self) -> PlotBounds {
|
||||||
*self.last_screen_transform.bounds()
|
*self.last_plot_transform.bounds()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the plot bounds. Can be useful for implementing alternative plot navigation methods.
|
/// Set the plot bounds. Can be useful for implementing alternative plot navigation methods.
|
||||||
|
|
@ -1090,18 +1107,23 @@ impl PlotUi {
|
||||||
/// The pointer drag delta in plot coordinates.
|
/// The pointer drag delta in plot coordinates.
|
||||||
pub fn pointer_coordinate_drag_delta(&self) -> Vec2 {
|
pub fn pointer_coordinate_drag_delta(&self) -> Vec2 {
|
||||||
let delta = self.response.drag_delta();
|
let delta = self.response.drag_delta();
|
||||||
let dp_dv = self.last_screen_transform.dpos_dvalue();
|
let dp_dv = self.last_plot_transform.dpos_dvalue();
|
||||||
Vec2::new(delta.x / dp_dv[0] as f32, delta.y / dp_dv[1] as f32)
|
Vec2::new(delta.x / dp_dv[0] as f32, delta.y / dp_dv[1] as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the transform netween plot coordinates and screen coordinates.
|
||||||
|
pub fn transform(&self) -> &PlotTransform {
|
||||||
|
&self.last_plot_transform
|
||||||
|
}
|
||||||
|
|
||||||
/// Transform the plot coordinates to screen coordinates.
|
/// Transform the plot coordinates to screen coordinates.
|
||||||
pub fn screen_from_plot(&self, position: PlotPoint) -> Pos2 {
|
pub fn screen_from_plot(&self, position: PlotPoint) -> Pos2 {
|
||||||
self.last_screen_transform.position_from_point(&position)
|
self.last_plot_transform.position_from_point(&position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform the screen coordinates to plot coordinates.
|
/// Transform the screen coordinates to plot coordinates.
|
||||||
pub fn plot_from_screen(&self, position: Pos2) -> PlotPoint {
|
pub fn plot_from_screen(&self, position: Pos2) -> PlotPoint {
|
||||||
self.last_screen_transform.value_from_position(position)
|
self.last_plot_transform.value_from_position(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a data line.
|
/// Add a data line.
|
||||||
|
|
@ -1299,7 +1321,7 @@ struct PreparedPlot {
|
||||||
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
|
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
|
||||||
axis_formatters: [AxisFormatter; 2],
|
axis_formatters: [AxisFormatter; 2],
|
||||||
show_axes: [bool; 2],
|
show_axes: [bool; 2],
|
||||||
transform: ScreenTransform,
|
transform: PlotTransform,
|
||||||
draw_cursor_x: bool,
|
draw_cursor_x: bool,
|
||||||
draw_cursor_y: bool,
|
draw_cursor_y: bool,
|
||||||
draw_cursors: Vec<Cursor>,
|
draw_cursors: Vec<Cursor>,
|
||||||
|
|
|
||||||
|
|
@ -181,10 +181,10 @@ impl PlotBounds {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains the screen rectangle and the plot bounds and provides methods to transform them.
|
/// Contains the screen rectangle and the plot bounds and provides methods to transform between them.
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) struct ScreenTransform {
|
pub struct PlotTransform {
|
||||||
/// The screen rectangle.
|
/// The screen rectangle.
|
||||||
frame: Rect,
|
frame: Rect,
|
||||||
|
|
||||||
|
|
@ -198,7 +198,7 @@ pub(crate) struct ScreenTransform {
|
||||||
y_centered: bool,
|
y_centered: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenTransform {
|
impl PlotTransform {
|
||||||
pub fn new(frame: Rect, mut bounds: PlotBounds, x_centered: bool, y_centered: bool) -> Self {
|
pub fn new(frame: Rect, mut bounds: PlotBounds, x_centered: bool, y_centered: bool) -> Self {
|
||||||
// Make sure they are not empty.
|
// Make sure they are not empty.
|
||||||
if !bounds.is_valid_x() {
|
if !bounds.is_valid_x() {
|
||||||
|
|
@ -229,15 +229,16 @@ impl ScreenTransform {
|
||||||
&self.frame
|
&self.frame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Plot-space bounds.
|
||||||
pub fn bounds(&self) -> &PlotBounds {
|
pub fn bounds(&self) -> &PlotBounds {
|
||||||
&self.bounds
|
&self.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_bounds(&mut self, bounds: PlotBounds) {
|
pub(crate) fn set_bounds(&mut self, bounds: PlotBounds) {
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn translate_bounds(&mut self, mut delta_pos: Vec2) {
|
pub(crate) fn translate_bounds(&mut self, mut delta_pos: Vec2) {
|
||||||
if self.x_centered {
|
if self.x_centered {
|
||||||
delta_pos.x = 0.;
|
delta_pos.x = 0.;
|
||||||
}
|
}
|
||||||
|
|
@ -250,7 +251,7 @@ impl ScreenTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zoom by a relative factor with the given screen position as center.
|
/// Zoom by a relative factor with the given screen position as center.
|
||||||
pub fn zoom(&mut self, zoom_factor: Vec2, center: Pos2) {
|
pub(crate) fn zoom(&mut self, zoom_factor: Vec2, center: Pos2) {
|
||||||
let center = self.value_from_position(center);
|
let center = self.value_from_position(center);
|
||||||
|
|
||||||
let mut new_bounds = self.bounds;
|
let mut new_bounds = self.bounds;
|
||||||
|
|
@ -280,6 +281,7 @@ impl ScreenTransform {
|
||||||
) as f32
|
) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Screen/ui position from point on plot.
|
||||||
pub fn position_from_point(&self, value: &PlotPoint) -> Pos2 {
|
pub fn position_from_point(&self, value: &PlotPoint) -> Pos2 {
|
||||||
pos2(
|
pos2(
|
||||||
self.position_from_point_x(value.x),
|
self.position_from_point_x(value.x),
|
||||||
|
|
@ -287,6 +289,7 @@ impl ScreenTransform {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Plot point from screen/ui position.
|
||||||
pub fn value_from_position(&self, pos: Pos2) -> PlotPoint {
|
pub fn value_from_position(&self, pos: Pos2) -> PlotPoint {
|
||||||
let x = remap(
|
let x = remap(
|
||||||
pos.x as f64,
|
pos.x as f64,
|
||||||
|
|
@ -335,6 +338,7 @@ impl ScreenTransform {
|
||||||
[1.0 / self.dpos_dvalue_x(), 1.0 / self.dpos_dvalue_y()]
|
[1.0 / self.dpos_dvalue_x(), 1.0 / self.dpos_dvalue_y()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// width / height aspect ratio
|
||||||
fn aspect(&self) -> f64 {
|
fn aspect(&self) -> f64 {
|
||||||
let rw = self.frame.width() as f64;
|
let rw = self.frame.width() as f64;
|
||||||
let rh = self.frame.height() as f64;
|
let rh = self.frame.height() as f64;
|
||||||
|
|
@ -344,7 +348,7 @@ impl ScreenTransform {
|
||||||
/// Sets the aspect ratio by expanding the x- or y-axis.
|
/// Sets the aspect ratio by expanding the x- or y-axis.
|
||||||
///
|
///
|
||||||
/// This never contracts, so we don't miss out on any data.
|
/// This never contracts, so we don't miss out on any data.
|
||||||
pub fn set_aspect_by_expanding(&mut self, aspect: f64) {
|
pub(crate) fn set_aspect_by_expanding(&mut self, aspect: f64) {
|
||||||
let current_aspect = self.aspect();
|
let current_aspect = self.aspect();
|
||||||
|
|
||||||
let epsilon = 1e-5;
|
let epsilon = 1e-5;
|
||||||
|
|
@ -363,7 +367,7 @@ impl ScreenTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the aspect ratio by changing either the X or Y axis (callers choice).
|
/// Sets the aspect ratio by changing either the X or Y axis (callers choice).
|
||||||
pub fn set_aspect_by_changing_axis(&mut self, aspect: f64, change_x: bool) {
|
pub(crate) fn set_aspect_by_changing_axis(&mut self, aspect: f64, change_x: bool) {
|
||||||
let current_aspect = self.aspect();
|
let current_aspect = self.aspect();
|
||||||
|
|
||||||
let epsilon = 1e-5;
|
let epsilon = 1e-5;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::f64::consts::TAU;
|
use std::f64::consts::TAU;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use egui::plot::{AxisBools, GridInput, GridMark};
|
use egui::plot::{AxisBools, GridInput, GridMark, PlotResponse};
|
||||||
use egui::*;
|
use egui::*;
|
||||||
use plot::{
|
use plot::{
|
||||||
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter, Corner, HLine,
|
Arrows, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter, Corner, HLine,
|
||||||
|
|
@ -751,9 +751,10 @@ impl InteractionDemo {
|
||||||
fn ui(&mut self, ui: &mut Ui) -> Response {
|
fn ui(&mut self, ui: &mut Ui) -> Response {
|
||||||
let plot = Plot::new("interaction_demo").height(300.0);
|
let plot = Plot::new("interaction_demo").height(300.0);
|
||||||
|
|
||||||
let InnerResponse {
|
let PlotResponse {
|
||||||
response,
|
response,
|
||||||
inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered),
|
inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered),
|
||||||
|
..
|
||||||
} = plot.show(ui, |plot_ui| {
|
} = plot.show(ui, |plot_ui| {
|
||||||
(
|
(
|
||||||
plot_ui.screen_from_plot(PlotPoint::new(0.0, 0.0)),
|
plot_ui.screen_from_plot(PlotPoint::new(0.0, 0.0)),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue