Skip to content

Commit

Permalink
fix(Barchart): horizontal labels were not displayed
Browse files Browse the repository at this point in the history
Fixed horizontal bars label not displayed.
Also adds ways to configure label truncation.
  • Loading branch information
Valentin271 committed Sep 19, 2023
1 parent 5498a88 commit 19ce368
Showing 1 changed file with 80 additions and 2 deletions.
82 changes: 80 additions & 2 deletions src/widgets/barchart.rs
Expand Up @@ -81,6 +81,8 @@ pub struct BarChart<'a> {
/// Value necessary for a bar to reach the maximum height (if no value is specified,
/// the maximum value in the data is taken as reference)
max: Option<u64>,
/// the maximum length of bars label
label_max_len: Option<u16>,
/// direction of the bars
direction: Direction,
}
Expand All @@ -99,6 +101,7 @@ impl<'a> Default for BarChart<'a> {
group_gap: 0,
bar_set: symbols::bar::NINE_LEVELS,
style: Style::default(),
label_max_len: None,
direction: Direction::Vertical,
}
}
Expand Down Expand Up @@ -258,6 +261,15 @@ impl<'a> BarChart<'a> {
self
}

/// Sets the maximum label length.
///
/// If not set, there is no maximum.
/// For horizontal bars, this effectively reserve the specified length.
pub fn label_max_len(mut self, len: u16) -> Self {
self.label_max_len = Some(len);
self
}

/// Set the direction of the bars.
///
/// [`Vertical`](crate::layout::Direction::Vertical) bars are the default.
Expand Down Expand Up @@ -335,6 +347,32 @@ impl<'a> BarChart<'a> {
}

fn render_horizontal_bars(self, buf: &mut Buffer, bars_area: Rect, max: u64) {
let label_size = if let Some(length) = self.label_max_len {
length
} else {
// get the longest label
self.data
.iter()
.map(|group| {
group
.bars
.iter()
.map(|bar| bar.label.clone().map_or(0, |label| label.width()))
.max()
.unwrap_or(0)
})
.max()
.unwrap_or(0) as u16
};

let margin = if label_size == 0 { 0 } else { 1 };

let bars_area = Rect {
x: bars_area.x + label_size + margin,
width: bars_area.width - label_size - margin,
..bars_area
};

// convert the bar values to ratatui::symbols::bar::Set
let groups: Vec<Vec<u16>> = self
.data
Expand All @@ -348,7 +386,7 @@ impl<'a> BarChart<'a> {
})
.collect();

// print all visible bars
// print all visible bars, label and values
let mut bar_y = bars_area.top();
for (group_data, mut group) in groups.into_iter().zip(self.data) {
let bars = std::mem::take(&mut group.bars);
Expand All @@ -374,6 +412,15 @@ impl<'a> BarChart<'a> {
y: bar_y + (self.bar_width >> 1),
..bars_area
};

// label
buf.set_line(
bars_area.left() - label_size - margin,
bar_value_area.top(),
&bar.label.clone().unwrap_or_default(),
label_size,
);

bar.render_value_with_different_styles(
buf,
bar_value_area,
Expand Down Expand Up @@ -487,7 +534,7 @@ impl<'a> BarChart<'a> {
for bar in bars.into_iter() {
bar.render_label_and_value(
buf,
self.bar_width,
u16::min(self.bar_width, self.label_max_len.unwrap_or(u16::MAX)),
bar_x,
bar_y,
self.value_style,
Expand Down Expand Up @@ -1093,6 +1140,37 @@ mod tests {
test_horizontal_bars_label_width_greater_than_bar(Some(Color::White))
}

/// Tests horizontal bars label are presents
#[test]
fn test_horizontal_label() {
let chart = BarChart::default()
.direction(Direction::Horizontal)
.bar_gap(0)
.data(&[("Jan", 10), ("Feb", 20), ("Mar", 5)]);

let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
chart.render(buffer.area, &mut buffer);
let expected = Buffer::with_lines(vec!["Jan 10█ ", "Feb 20████", "Mar 5 "]);

assert_buffer_eq!(buffer, expected);
}

/// Tests horizontal bars label are truncated
#[test]
fn test_horizontal_label_max_len() {
let chart = BarChart::default()
.direction(Direction::Horizontal)
.bar_gap(0)
.data(&[("January", 10), ("February", 20), ("March", 5)])
.label_max_len(1);

let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
chart.render(buffer.area, &mut buffer);
let expected = Buffer::with_lines(vec!["J 10██ ", "F 20██████", "M 5█ "]);

assert_buffer_eq!(buffer, expected);
}

#[test]
fn test_group_label_style() {
let chart: BarChart<'_> = BarChart::default()
Expand Down

0 comments on commit 19ce368

Please sign in to comment.