Skip to content

Commit b9d844a

Browse files
committed
replace Option by more descriptive HoverPosition enum
I'd love to get rid of the lifetime annotations, but my Rust fu isn't good enough for that.
1 parent f8a3ed7 commit b9d844a

File tree

3 files changed

+58
-16
lines changed

3 files changed

+58
-16
lines changed

demo/src/plot_demo.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use egui::{
88

99
use egui_plot::{
1010
Arrows, AxisHints, Bar, BarChart, BoxElem, BoxPlot, BoxSpread, CoordinatesFormatter, Corner,
11-
GridInput, GridMark, HLine, Legend, Line, LineStyle, MarkerShape, Plot, PlotImage, PlotPoint,
12-
PlotPoints, PlotResponse, Points, Polygon, Text, VLine,
11+
GridInput, GridMark, HLine, HoverPosition, Legend, Line, LineStyle, MarkerShape, Plot,
12+
PlotImage, PlotPoint, PlotPoints, PlotResponse, Points, Polygon, Text, VLine,
1313
};
1414

1515
// ----------------------------------------------------------------------------
@@ -636,14 +636,19 @@ impl CustomAxesDemo {
636636
}
637637
};
638638

639-
let label_fmt = |_nearest: Option<(&str, usize)>, val: &PlotPoint| {
640-
Some(format!(
639+
let label_fmt = |position: &HoverPosition<'_>| match position {
640+
HoverPosition::NearDataPoint {
641+
plot_name: _,
642+
position,
643+
index: _,
644+
} => Some(format!(
641645
"Day {d}, {h}:{m:02}\n{p:.2}%",
642-
d = day(val.x),
643-
h = hour(val.x),
644-
m = minute(val.x),
645-
p = percent(val.y)
646-
))
646+
d = day(position.x),
647+
h = hour(position.x),
648+
m = minute(position.x),
649+
p = percent(position.y)
650+
)),
651+
HoverPosition::Elsewhere { position: _ } => None,
647652
};
648653

649654
ui.label("Zoom in on the X-axis to see hours and minutes");

egui_plot/src/items/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use egui::{
1414
use emath::Float as _;
1515
use rect_elem::{RectElement, highlighted_color};
1616

17+
use crate::HoverPosition;
18+
1719
use super::{Cursor, NewLabelFormatter, PlotBounds, PlotTransform};
1820

1921
pub use bar::Bar;
@@ -1708,7 +1710,15 @@ pub(super) fn rulers_and_tooltip_at_value(
17081710
}
17091711

17101712
let text = if let Some(custom_label) = label_formatter {
1711-
custom_label(nearest_point, &value)
1713+
let hover_position = match nearest_point {
1714+
Some((name, index)) => HoverPosition::NearDataPoint {
1715+
plot_name: name,
1716+
position: value,
1717+
index: index,
1718+
},
1719+
None => HoverPosition::Elsewhere { position: value },
1720+
};
1721+
custom_label(&hover_position)
17121722
} else {
17131723
let prefix = if let Some((name, _)) = nearest_point {
17141724
format!("{name}\n")

egui_plot/src/lib.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use legend::LegendWidget;
4545
type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a;
4646
pub type LabelFormatter<'a> = Option<Box<LabelFormatterFn<'a>>>;
4747

48-
type NewLabelFormatterFn<'a> = dyn Fn(Option<(&str, usize)>, &PlotPoint) -> Option<String> + 'a;
48+
type NewLabelFormatterFn<'a> = dyn Fn(&HoverPosition<'_>) -> Option<String> + 'a;
4949
pub type NewLabelFormatter<'a> = Option<Box<NewLabelFormatterFn<'a>>>;
5050

5151
type GridSpacerFn<'a> = dyn Fn(GridInput) -> Vec<GridMark> + 'a;
@@ -95,6 +95,23 @@ pub enum Cursor {
9595
Vertical { x: f64 },
9696
}
9797

98+
/// Indicates the position of the cursor in a plot for hover purposes.
99+
#[derive(Copy, Clone, PartialEq)]
100+
pub enum HoverPosition<'a> {
101+
NearDataPoint {
102+
/// The name of the plot whose data point is nearest to the cursor
103+
plot_name: &'a str,
104+
/// The position of the nearest data point
105+
position: PlotPoint,
106+
/// The index of the nearest data point in its plot
107+
index: usize,
108+
},
109+
Elsewhere {
110+
/// The position in the plot over which the cursor hovers
111+
position: PlotPoint,
112+
},
113+
}
114+
98115
/// Contains the cursors drawn for a plot widget in a single frame.
99116
#[derive(PartialEq, Clone)]
100117
struct PlotFrameCursors {
@@ -430,8 +447,15 @@ impl<'a> Plot<'a> {
430447
label_formatter: impl Fn(&str, &PlotPoint) -> String + 'a,
431448
) -> Self {
432449
let inner_box = Box::new(label_formatter);
433-
self.label_formatter = Some(Box::new(move |option, point| {
434-
Some(inner_box(option.map_or("", |(name, _)| name), point))
450+
self.label_formatter = Some(Box::new(move |position| {
451+
Some(match position {
452+
HoverPosition::NearDataPoint {
453+
plot_name,
454+
position,
455+
index: _,
456+
} => inner_box(plot_name, &position),
457+
HoverPosition::Elsewhere { position: _ } => "".to_owned(),
458+
})
435459
}));
436460
self
437461
}
@@ -449,15 +473,18 @@ impl<'a> Plot<'a> {
449473
/// }).collect();
450474
/// let line = Line::new("sin", sin);
451475
/// Plot::new("my_plot").view_aspect(2.0)
452-
/// .enumerated_label_formatter(|nearest_point, value| {
453-
/// nearest_point.map(|(name, _index)| format!("{}: {:.*}%", name, 1, value.y))
476+
/// .enumerated_label_formatter(|context| {
477+
/// match context {
478+
/// Some((name, index)) => format!("{}: {:.*}%", name, 1, index),
479+
/// Elsewhere { ... } => None,
480+
/// }
454481
/// })
455482
/// .show(ui, |plot_ui| plot_ui.line(line));
456483
/// # });
457484
/// ```
458485
pub fn enumerated_label_formatter(
459486
mut self,
460-
label_formatter: impl Fn(Option<(&str, usize)>, &PlotPoint) -> Option<String> + 'a,
487+
label_formatter: impl Fn(&HoverPosition<'_>) -> Option<String> + 'a,
461488
) -> Self {
462489
self.label_formatter = Some(Box::new(label_formatter));
463490
self

0 commit comments

Comments
 (0)