Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Providing more control over hover label in plots #1046

Closed
wants to merge 12 commits into from
4 changes: 2 additions & 2 deletions egui/src/widgets/plot/items/bar.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Shape, Stroke};
use crate::plot::items::num_decimals_with_max_digits;

use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BarChart, ScreenTransform, Value};
Expand Down Expand Up @@ -184,7 +184,7 @@ impl RectElement for Bar {

fn default_values_format(&self, transform: &ScreenTransform) -> String {
let scale = transform.dvalue_dpos();
let y_decimals = ((-scale[1].abs().log10()).ceil().at_least(0.0) as usize).at_most(6);
let y_decimals = num_decimals_with_max_digits(scale[1], 6);
format!("\n{:.*}", y_decimals, self.value)
}
}
4 changes: 2 additions & 2 deletions egui/src/widgets/plot/items/box_elem.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::emath::NumExt;
use crate::epaint::{Color32, RectShape, Shape, Stroke};
use crate::plot::items::num_decimals_with_max_digits;

use super::{add_rulers_and_text, highlighted_color, Orientation, PlotConfig, RectElement};
use crate::plot::{BoxPlot, ScreenTransform, Value};
Expand Down Expand Up @@ -268,7 +268,7 @@ impl RectElement for BoxElem {

fn default_values_format(&self, transform: &ScreenTransform) -> String {
let scale = transform.dvalue_dpos();
let y_decimals = ((-scale[1].abs().log10()).ceil().at_least(0.0) as usize).at_most(6);
let y_decimals = num_decimals_with_max_digits(scale[1], 6);
format!(
"\nMax = {max:.decimals$}\
\nQuartile 3 = {q3:.decimals$}\
Expand Down
107 changes: 41 additions & 66 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::*;

use super::{CustomLabelFuncRef, PlotBounds, ScreenTransform};
use super::{HoverFormatter, HoverLine, PlotBounds, ScreenTransform};
use rect_elem::*;
use values::{ClosestElem, PlotGeometry};

Expand All @@ -26,8 +26,13 @@ const DEFAULT_FILL_ALPHA: f32 = 0.05;
pub(super) struct PlotConfig<'a> {
pub ui: &'a Ui,
pub transform: &'a ScreenTransform,
pub show_x: bool,
pub show_y: bool,
pub hover_config: HoverConfig,
pub hover_formatter: &'a HoverFormatter,
}

pub struct HoverConfig {
pub hover_line: HoverLine,
pub show_hover_label: bool,
}

/// Trait shared by things that can be drawn in the plot.
Expand Down Expand Up @@ -61,13 +66,7 @@ pub(super) trait PlotItem {
}
}

fn on_hover(
&self,
elem: ClosestElem,
shapes: &mut Vec<Shape>,
plot: &PlotConfig<'_>,
custom_label_func: &CustomLabelFuncRef,
) {
fn on_hover(&self, elem: ClosestElem, shapes: &mut Vec<Shape>, plot: &PlotConfig<'_>) {
let points = match self.geometry() {
PlotGeometry::Points(points) => points,
PlotGeometry::None => {
Expand All @@ -89,7 +88,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, custom_label_func);
rulers_at_value(pointer, value, self.name(), plot, shapes);
}
}

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

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

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

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

box_plot.add_shapes(plot.transform, true, shapes);
Expand Down Expand Up @@ -1570,11 +1557,14 @@ fn add_rulers_and_text(
text: Option<String>,
shapes: &mut Vec<Shape>,
) {
let hover_config = &plot.hover_config;

let orientation = elem.orientation();
let show_argument = plot.show_x && orientation == Orientation::Vertical
|| plot.show_y && orientation == Orientation::Horizontal;
let show_values = plot.show_y && orientation == Orientation::Vertical
|| plot.show_x && orientation == Orientation::Horizontal;
let show_argument = hover_config.hover_line.show_x_line()
&& orientation == Orientation::Vertical
|| hover_config.hover_line.show_y_line() && orientation == Orientation::Horizontal;
let show_values = hover_config.hover_line.show_y_line() && orientation == Orientation::Vertical
|| hover_config.hover_line.show_x_line() && orientation == Orientation::Horizontal;

let line_color = rulers_color(plot.ui);

Expand Down Expand Up @@ -1643,52 +1633,32 @@ pub(super) fn rulers_at_value(
name: &str,
plot: &PlotConfig<'_>,
shapes: &mut Vec<Shape>,
custom_label_func: &CustomLabelFuncRef,
) {
let hover_config = &plot.hover_config;

let line_color = rulers_color(plot.ui);
if plot.show_x {
if hover_config.hover_line.show_x_line() {
shapes.push(vertical_line(pointer, plot.transform, line_color));
}
if plot.show_y {
if hover_config.hover_line.show_y_line() {
shapes.push(horizontal_line(pointer, plot.transform, line_color));
}

let mut prefix = String::new();

if !name.is_empty() {
prefix = format!("{}\n", name);
}

let text = {
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 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
)
} else if plot.show_x {
format!("{}x = {:.*}", prefix, x_decimals, value.x)
} else if plot.show_y {
format!("{}y = {:.*}", prefix, y_decimals, value.y)
} else {
unreachable!()
}
};
if hover_config.show_hover_label {
let hover_label_func = plot.hover_formatter;
let text = hover_label_func(&plot.hover_config, name, &value);

let font_id = TextStyle::Body.resolve(plot.ui.style());
let font_id = TextStyle::Body.resolve(plot.ui.style());

shapes.push(Shape::text(
&*plot.ui.fonts(),
pointer + vec2(3.0, -2.0),
Align2::LEFT_BOTTOM,
text,
font_id,
plot.ui.visuals().text_color(),
));
shapes.push(Shape::text(
&*plot.ui.fonts(),
pointer + vec2(3.0, -2.0),
Align2::LEFT_BOTTOM,
text,
font_id,
plot.ui.visuals().text_color(),
));
}
}

fn find_closest_rect<'a, T>(
Expand All @@ -1710,3 +1680,8 @@ where
})
.min_by_key(|e| e.dist_sq.ord())
}

/// Returns the number of decimals required to show the specified maximum number of digits
pub(super) fn num_decimals_with_max_digits(value: f64, max_digits: usize) -> usize {
max_digits - ((value.abs().log10()).ceil().at_least(0.0) as usize).at_most(max_digits)
}
Loading