mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-21 20:23:11 +00:00
feat(sparkline): Add show baseline option
Adds an option to the sparkline widget to render the minimum value as a baseline symbol rather than as an empty cell.
This commit is contained in:
parent
9da02078fe
commit
4f5594beff
1 changed files with 104 additions and 11 deletions
|
@ -31,6 +31,8 @@ pub struct Sparkline<'a> {
|
|||
/// The maximum value to take to compute the maximum bar height (if nothing is specified, the
|
||||
/// widget uses the max of the dataset)
|
||||
max: Option<u64>,
|
||||
/// If true, draws a baseline of `bar::ONE_EIGHTH` spanning the bottom of the sparkline graph
|
||||
show_baseline: bool,
|
||||
/// A set of bar symbols used to represent the give data
|
||||
bar_set: symbols::bar::Set,
|
||||
// The direction to render the sparkine, either from left to right, or from right to left
|
||||
|
@ -50,6 +52,7 @@ impl<'a> Default for Sparkline<'a> {
|
|||
style: Default::default(),
|
||||
data: &[],
|
||||
max: None,
|
||||
show_baseline: false,
|
||||
bar_set: symbols::bar::NINE_LEVELS,
|
||||
direction: RenderDirection::LeftToRight,
|
||||
}
|
||||
|
@ -77,6 +80,11 @@ impl<'a> Sparkline<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn show_baseline(mut self, show_baseline: bool) -> Sparkline<'a> {
|
||||
self.show_baseline = show_baseline;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> Sparkline<'a> {
|
||||
self.bar_set = bar_set;
|
||||
self
|
||||
|
@ -103,6 +111,14 @@ impl<'a> Widget for Sparkline<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
if self.show_baseline {
|
||||
for i in spark_area.left()..spark_area.right() {
|
||||
buf.get_mut(i, spark_area.bottom() - 1)
|
||||
.set_symbol(self.bar_set.one_eighth)
|
||||
.set_style(self.style);
|
||||
}
|
||||
}
|
||||
|
||||
let max = match self.max {
|
||||
Some(v) => v,
|
||||
None => *self.data.iter().max().unwrap_or(&1u64),
|
||||
|
@ -123,7 +139,13 @@ impl<'a> Widget for Sparkline<'a> {
|
|||
for j in (0..spark_area.height).rev() {
|
||||
for (i, d) in data.iter_mut().enumerate() {
|
||||
let symbol = match *d {
|
||||
0 => self.bar_set.empty,
|
||||
0 => {
|
||||
if self.show_baseline && j == spark_area.height - 1 {
|
||||
self.bar_set.one_eighth
|
||||
} else {
|
||||
self.bar_set.empty
|
||||
}
|
||||
}
|
||||
1 => self.bar_set.one_eighth,
|
||||
2 => self.bar_set.one_quarter,
|
||||
3 => self.bar_set.three_eighths,
|
||||
|
@ -158,42 +180,94 @@ mod tests {
|
|||
|
||||
// Helper function to render a sparkline to a buffer with a given width
|
||||
// filled with x symbols to make it easier to assert on the result
|
||||
fn render(widget: Sparkline, width: u16) -> Buffer {
|
||||
let area = Rect::new(0, 0, width, 1);
|
||||
fn render(widget: Sparkline, width: u16, height: u16) -> Buffer {
|
||||
let mut cell = Cell::default();
|
||||
cell.set_symbol("x");
|
||||
let mut buffer = Buffer::filled(area, &cell);
|
||||
widget.render(area, &mut buffer);
|
||||
let mut buffer = Buffer::filled(Rect::new(0, 0, width, height), &cell);
|
||||
widget.render(buffer.area, &mut buffer);
|
||||
buffer
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_does_not_panic_if_max_is_zero() {
|
||||
let widget = Sparkline::default().data(&[0, 0, 0]);
|
||||
let buffer = render(widget, 6);
|
||||
let buffer = render(widget, 6, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" xxx"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_does_not_panic_if_max_is_set_to_zero() {
|
||||
let widget = Sparkline::default().data(&[0, 1, 2]).max(0);
|
||||
let buffer = render(widget, 6);
|
||||
let buffer = render(widget, 6, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" xxx"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_draws() {
|
||||
fn it_renders() {
|
||||
let widget = Sparkline::default().data(&[0, 1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
let buffer = render(widget, 12);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" ▁▂▃▄▅▆▇█xxx"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_with_max_more_than_data_max() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.max(16);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" ▁▁▂▂▃▃▄xxx"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_with_max_less_than_data_max() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.max(4);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" ▂▄▆█████xxx"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_with_multi_line() {
|
||||
let widget = Sparkline::default().data(&[0, 1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
let buffer = render(widget, 15, 3);
|
||||
assert_buffer_eq!(
|
||||
buffer,
|
||||
Buffer::with_lines(vec![
|
||||
" ▂▅█xxxxxx",
|
||||
" ▁▄▇███xxxxxx",
|
||||
" ▃▆██████xxxxxx",
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_with_multi_line_and_baseline() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.show_baseline(true);
|
||||
let buffer = render(widget, 15, 3);
|
||||
assert_buffer_eq!(
|
||||
buffer,
|
||||
// this currently fails because the baseline logic doesn't clear
|
||||
// the parts above the line
|
||||
// " ▂▅█xxxxxx",
|
||||
// " ▁▄▇███xxxxxx",
|
||||
// " ▃▆██████▁▁▁▁▁▁",
|
||||
Buffer::with_lines(vec![
|
||||
" ▂▅█ ",
|
||||
" ▁▄▇███ ",
|
||||
" ▃▆██████▁▁▁▁▁▁",
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_left_to_right() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.direction(RenderDirection::LeftToRight);
|
||||
let buffer = render(widget, 12);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec![" ▁▂▃▄▅▆▇█xxx"]));
|
||||
}
|
||||
|
||||
|
@ -202,7 +276,26 @@ mod tests {
|
|||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.direction(RenderDirection::RightToLeft);
|
||||
let buffer = render(widget, 12);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec!["xxx█▇▆▅▄▃▂▁ "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_baseline() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.show_baseline(true);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec!["▁▁▂▃▄▅▆▇█▁▁▁"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_renders_baseline_right_to_left() {
|
||||
let widget = Sparkline::default()
|
||||
.data(&[0, 1, 2, 3, 4, 5, 6, 7, 8])
|
||||
.direction(RenderDirection::RightToLeft)
|
||||
.show_baseline(true);
|
||||
let buffer = render(widget, 12, 1);
|
||||
assert_buffer_eq!(buffer, Buffer::with_lines(vec!["▁▁▁█▇▆▅▄▃▂▁▁"]));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue