parent
e4e1638fc0
commit
99af63fad2
5 changed files with 80 additions and 12 deletions
|
@ -8,8 +8,11 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
|
|||
### Added ⭐
|
||||
* `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)).
|
||||
* Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider.
|
||||
* Improved plot grid appearance ([#2412](https://github.com/emilk/egui/pull/2412)).
|
||||
* Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)).
|
||||
* Add `Plot::clamp_grid` to only show grid where there is data ([#2480](https://github.com/emilk/egui/pull/2480)).
|
||||
|
||||
### Changed 🔧
|
||||
* Improved plot grid appearance ([#2412](https://github.com/emilk/egui/pull/2412)).
|
||||
|
||||
### Fixed 🐛
|
||||
* Expose `TextEdit`'s multiline flag to AccessKit ([#2448](https://github.com/emilk/egui/pull/2448)).
|
||||
|
|
|
@ -34,6 +34,7 @@ pub(super) struct PlotConfig<'a> {
|
|||
pub(super) trait PlotItem {
|
||||
fn shapes(&self, ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec<Shape>);
|
||||
|
||||
/// For plot-items which are generated based on x values (plotting functions).
|
||||
fn initialize(&mut self, x_range: RangeInclusive<f64>);
|
||||
|
||||
fn name(&self) -> &str;
|
||||
|
|
|
@ -291,8 +291,10 @@ pub struct Plot {
|
|||
legend_config: Option<Legend>,
|
||||
show_background: bool,
|
||||
show_axes: [bool; 2],
|
||||
|
||||
grid_spacers: [GridSpacer; 2],
|
||||
sharp_grid_lines: bool,
|
||||
clamp_grid: bool,
|
||||
}
|
||||
|
||||
impl Plot {
|
||||
|
@ -331,8 +333,10 @@ impl Plot {
|
|||
legend_config: None,
|
||||
show_background: true,
|
||||
show_axes: [true; 2],
|
||||
|
||||
grid_spacers: [log_grid_spacer(10), log_grid_spacer(10)],
|
||||
sharp_grid_lines: true,
|
||||
clamp_grid: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,6 +561,14 @@ impl Plot {
|
|||
self
|
||||
}
|
||||
|
||||
/// Clamp the grid to only be visible at the range of data where we have values.
|
||||
///
|
||||
/// Default: `false`.
|
||||
pub fn clamp_grid(mut self, clamp_grid: bool) -> Self {
|
||||
self.clamp_grid = clamp_grid;
|
||||
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 {
|
||||
|
@ -671,6 +683,8 @@ impl Plot {
|
|||
show_axes,
|
||||
linked_axes,
|
||||
linked_cursors,
|
||||
|
||||
clamp_grid,
|
||||
grid_spacers,
|
||||
sharp_grid_lines,
|
||||
} = self;
|
||||
|
@ -971,11 +985,12 @@ impl Plot {
|
|||
axis_formatters,
|
||||
show_axes,
|
||||
transform: transform.clone(),
|
||||
grid_spacers,
|
||||
draw_cursor_x: linked_cursors.as_ref().map_or(false, |group| group.link_x),
|
||||
draw_cursor_y: linked_cursors.as_ref().map_or(false, |group| group.link_y),
|
||||
draw_cursors,
|
||||
grid_spacers,
|
||||
sharp_grid_lines,
|
||||
clamp_grid,
|
||||
};
|
||||
let plot_cursors = prepared.ui(ui, &response);
|
||||
|
||||
|
@ -1297,11 +1312,13 @@ struct PreparedPlot {
|
|||
axis_formatters: [AxisFormatter; 2],
|
||||
show_axes: [bool; 2],
|
||||
transform: ScreenTransform,
|
||||
grid_spacers: [GridSpacer; 2],
|
||||
draw_cursor_x: bool,
|
||||
draw_cursor_y: bool,
|
||||
draw_cursors: Vec<Cursor>,
|
||||
|
||||
grid_spacers: [GridSpacer; 2],
|
||||
sharp_grid_lines: bool,
|
||||
clamp_grid: bool,
|
||||
}
|
||||
|
||||
impl PreparedPlot {
|
||||
|
@ -1400,10 +1417,13 @@ impl PreparedPlot {
|
|||
shapes: &mut Vec<(Shape, f32)>,
|
||||
sharp_grid_lines: bool,
|
||||
) {
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
|
||||
let Self {
|
||||
transform,
|
||||
axis_formatters,
|
||||
grid_spacers,
|
||||
clamp_grid,
|
||||
..
|
||||
} = self;
|
||||
|
||||
|
@ -1417,7 +1437,6 @@ impl PreparedPlot {
|
|||
let font_id = TextStyle::Body.resolve(ui.style());
|
||||
|
||||
// Where on the cross-dimension to show the label values
|
||||
let bounds = transform.bounds();
|
||||
let value_cross = 0.0_f64.clamp(bounds.min[1 - axis], bounds.max[1 - axis]);
|
||||
|
||||
let input = GridInput {
|
||||
|
@ -1426,9 +1445,31 @@ impl PreparedPlot {
|
|||
};
|
||||
let steps = (grid_spacers[axis])(input);
|
||||
|
||||
let clamp_range = clamp_grid.then(|| {
|
||||
let mut tight_bounds = PlotBounds::NOTHING;
|
||||
for item in &self.items {
|
||||
let item_bounds = item.bounds();
|
||||
tight_bounds.merge_x(&item_bounds);
|
||||
tight_bounds.merge_y(&item_bounds);
|
||||
}
|
||||
tight_bounds
|
||||
});
|
||||
|
||||
for step in steps {
|
||||
let value_main = step.value;
|
||||
|
||||
if let Some(clamp_range) = clamp_range {
|
||||
if axis == 0 {
|
||||
if !clamp_range.range_x().contains(&value_main) {
|
||||
continue;
|
||||
};
|
||||
} else {
|
||||
if !clamp_range.range_y().contains(&value_main) {
|
||||
continue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let value = if axis == 0 {
|
||||
PlotPoint::new(value_main, value_cross)
|
||||
} else {
|
||||
|
@ -1451,11 +1492,23 @@ impl PreparedPlot {
|
|||
let mut p1 = pos_in_gui;
|
||||
p0[1 - axis] = transform.frame().min[1 - axis];
|
||||
p1[1 - axis] = transform.frame().max[1 - axis];
|
||||
|
||||
if let Some(clamp_range) = clamp_range {
|
||||
if axis == 0 {
|
||||
p0.y = transform.position_from_point_y(clamp_range.min[1]);
|
||||
p1.y = transform.position_from_point_y(clamp_range.max[1]);
|
||||
} else {
|
||||
p0.x = transform.position_from_point_x(clamp_range.min[0]);
|
||||
p1.x = transform.position_from_point_x(clamp_range.max[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if sharp_grid_lines {
|
||||
// Round to avoid aliasing
|
||||
p0 = ui.ctx().round_pos_to_pixels(p0);
|
||||
p1 = ui.ctx().round_pos_to_pixels(p1);
|
||||
}
|
||||
|
||||
shapes.push((
|
||||
Shape::line_segment([p0, p1], Stroke::new(1.0, line_color)),
|
||||
line_strength,
|
||||
|
|
|
@ -224,6 +224,7 @@ impl ScreenTransform {
|
|||
}
|
||||
}
|
||||
|
||||
/// ui-space rectangle.
|
||||
pub fn frame(&self) -> &Rect {
|
||||
&self.frame
|
||||
}
|
||||
|
@ -263,18 +264,27 @@ impl ScreenTransform {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn position_from_point(&self, value: &PlotPoint) -> Pos2 {
|
||||
let x = remap(
|
||||
value.x,
|
||||
pub fn position_from_point_x(&self, value: f64) -> f32 {
|
||||
remap(
|
||||
value,
|
||||
self.bounds.min[0]..=self.bounds.max[0],
|
||||
(self.frame.left() as f64)..=(self.frame.right() as f64),
|
||||
);
|
||||
let y = remap(
|
||||
value.y,
|
||||
) as f32
|
||||
}
|
||||
|
||||
pub fn position_from_point_y(&self, value: f64) -> f32 {
|
||||
remap(
|
||||
value,
|
||||
self.bounds.min[1]..=self.bounds.max[1],
|
||||
(self.frame.bottom() as f64)..=(self.frame.top() as f64), // negated y axis!
|
||||
);
|
||||
pos2(x as f32, y as f32)
|
||||
) as f32
|
||||
}
|
||||
|
||||
pub fn position_from_point(&self, value: &PlotPoint) -> Pos2 {
|
||||
pos2(
|
||||
self.position_from_point_x(value.x),
|
||||
self.position_from_point_y(value.y),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn value_from_position(&self, pos: Pos2) -> PlotPoint {
|
||||
|
|
|
@ -755,6 +755,7 @@ impl ChartsDemo {
|
|||
Plot::new("Normal Distribution Demo")
|
||||
.legend(Legend::default())
|
||||
.data_aspect(1.0)
|
||||
.clamp_grid(true)
|
||||
.show(ui, |plot_ui| plot_ui.bar_chart(chart))
|
||||
.response
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue