Skip to content

Commit

Permalink
Add ability to customize the display of hover plot labels
Browse files Browse the repository at this point in the history
  • Loading branch information
isegal committed Dec 6, 2021
1 parent c85eca6 commit 4f17c3f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 8 deletions.
33 changes: 27 additions & 6 deletions egui/src/widgets/plot/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use epaint::Mesh;
use crate::util::float_ord::FloatOrd;
use crate::*;

use super::{PlotBounds, ScreenTransform};
use super::{CustomLabelFunc, PlotBounds, ScreenTransform};
use rect_elem::*;
use values::*;

Expand Down Expand Up @@ -61,7 +61,13 @@ pub(super) trait PlotItem {
}
}

fn on_hover(&self, elem: ClosestElem, shapes: &mut Vec<Shape>, plot: &PlotConfig<'_>) {
fn on_hover(
&self,
elem: ClosestElem,
shapes: &mut Vec<Shape>,
plot: &PlotConfig<'_>,
custom_label_func: &CustomLabelFunc,
) {
let points = match self.geometry() {
PlotGeometry::Points(points) => points,
PlotGeometry::None => {
Expand All @@ -83,7 +89,7 @@ pub(super) trait PlotItem {
let pointer = plot.transform.position_from_value(&value);
shapes.push(Shape::circle_filled(pointer, 3.0, line_color));

rulers_at_value(pointer, value, self.name(), plot, shapes);
rulers_at_value(pointer, value, self.name(), plot, shapes, custom_label_func);
}
}

Expand Down Expand Up @@ -1365,7 +1371,13 @@ impl PlotItem for BarChart {
find_closest_rect(&self.bars, point, transform)
}

fn on_hover(&self, elem: ClosestElem, shapes: &mut Vec<Shape>, plot: &PlotConfig<'_>) {
fn on_hover(
&self,
elem: ClosestElem,
shapes: &mut Vec<Shape>,
plot: &PlotConfig<'_>,
_: &CustomLabelFunc,
) {
let bar = &self.bars[elem.index];

bar.add_shapes(plot.transform, true, shapes);
Expand Down Expand Up @@ -1501,7 +1513,13 @@ impl PlotItem for BoxPlot {
find_closest_rect(&self.boxes, point, transform)
}

fn on_hover(&self, elem: ClosestElem, shapes: &mut Vec<Shape>, plot: &PlotConfig<'_>) {
fn on_hover(
&self,
elem: ClosestElem,
shapes: &mut Vec<Shape>,
plot: &PlotConfig<'_>,
_: &CustomLabelFunc,
) {
let box_plot = &self.boxes[elem.index];

box_plot.add_shapes(plot.transform, true, shapes);
Expand Down Expand Up @@ -1619,6 +1637,7 @@ pub(super) fn rulers_at_value(
name: &str,
plot: &PlotConfig<'_>,
shapes: &mut Vec<Shape>,
custom_label_func: &CustomLabelFunc,
) {
let line_color = rulers_color(plot.ui);
if plot.show_x {
Expand All @@ -1638,7 +1657,9 @@ pub(super) fn rulers_at_value(
let scale = plot.transform.dvalue_dpos();
let x_decimals = ((-scale[0].abs().log10()).ceil().at_least(0.0) as usize).at_most(6);
let y_decimals = ((-scale[1].abs().log10()).ceil().at_least(0.0) as usize).at_most(6);
if plot.show_x && plot.show_y {
if let Some(custom_label) = custom_label_func {
custom_label(name, &value)
} else if plot.show_x && plot.show_y {
format!(
"{}x = {:.*}\ny = {:.*}",
prefix, x_decimals, value.x, y_decimals, value.y
Expand Down
38 changes: 36 additions & 2 deletions egui/src/widgets/plot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ mod items;
mod legend;
mod transform;

type CustomLabelFunc = Option<Box<dyn Fn(&str, &Value) -> String>>;

// ----------------------------------------------------------------------------

/// Information about the plot that has to persist between frames.
Expand Down Expand Up @@ -76,6 +78,7 @@ pub struct Plot {

show_x: bool,
show_y: bool,
custom_label_func: CustomLabelFunc,
legend_config: Option<Legend>,
show_background: bool,
show_axes: [bool; 2],
Expand All @@ -102,6 +105,7 @@ impl Plot {

show_x: true,
show_y: true,
custom_label_func: None,
legend_config: None,
show_background: true,
show_axes: [true; 2],
Expand Down Expand Up @@ -182,6 +186,32 @@ impl Plot {
self
}

/// Provide a function to customize the on-hovel label for the x and y axis
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// use egui::plot::{Line, Plot, Value, Values};
/// let sin = (0..1000).map(|i| {
/// let x = i as f64 * 0.01;
/// Value::new(x, x.sin())
/// });
/// let line = Line::new(Values::from_values_iter(sin));
/// Plot::new("my_plot").view_aspect(2.0)
/// .custom_label_func(Some(Box::new(|name, value| {
/// if !name.is_empty() {
/// format!("{}: {:.*}%", name, 1, value.y).to_string()
/// } else {
/// "".to_string()
/// }
/// })))
/// .show(ui, |plot_ui| plot_ui.line(line));
/// # });
/// ```
pub fn custom_label_func(mut self, custom_lebel_func: CustomLabelFunc) -> Self {
self.custom_label_func = custom_lebel_func;
self
}

/// Expand bounds to include the given x value.
/// For instance, to always show the y axis, call `plot.include_x(0.0)`.
pub fn include_x(mut self, x: impl Into<f64>) -> Self {
Expand Down Expand Up @@ -235,6 +265,7 @@ impl Plot {
view_aspect,
mut show_x,
mut show_y,
custom_label_func,
legend_config,
show_background,
show_axes,
Expand Down Expand Up @@ -406,6 +437,7 @@ impl Plot {
items,
show_x,
show_y,
custom_label_func,
show_axes,
transform: transform.clone(),
};
Expand Down Expand Up @@ -613,6 +645,7 @@ struct PreparedPlot {
items: Vec<Box<dyn PlotItem>>,
show_x: bool,
show_y: bool,
custom_label_func: CustomLabelFunc,
show_axes: [bool; 2],
transform: ScreenTransform,
}
Expand Down Expand Up @@ -731,6 +764,7 @@ impl PreparedPlot {
transform,
show_x,
show_y,
custom_label_func,
items,
..
} = self;
Expand Down Expand Up @@ -760,10 +794,10 @@ impl PreparedPlot {
};

if let Some((item, elem)) = closest {
item.on_hover(elem, shapes, &plot);
item.on_hover(elem, shapes, &plot, custom_label_func);
} else {
let value = transform.value_from_position(pointer);
items::rulers_at_value(pointer, value, "", &plot, shapes);
items::rulers_at_value(pointer, value, "", &plot, shapes, custom_label_func);
}
}
}

0 comments on commit 4f17c3f

Please sign in to comment.