From cee65ed2833dab66625f9f30593ae870f98e3ccf Mon Sep 17 00:00:00 2001 From: Florian Dehau Date: Tue, 14 Apr 2020 00:57:50 +0200 Subject: [PATCH] feat: allow BarChart and Sparkline to use a more portable set of symbols Add `BarChart::bar_set` and `Sparkline::bar_set` methods to customize the set of symbols used to display the data. The new set should give a better looking output on terminal that do not support a wide range of unicode symbols. --- src/symbols.rs | 72 ++++++++++++++++++++++++++++++++++++++++ src/widgets/barchart.rs | 45 ++++++++++++++++--------- src/widgets/sparkline.rs | 39 +++++++++++++--------- 3 files changed, 125 insertions(+), 31 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 7583496..d6fcdf4 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -7,6 +7,42 @@ pub mod block { pub const THREE_EIGHTHS: &str = "▍"; pub const ONE_QUARTER: &str = "▎"; pub const ONE_EIGHTH: &str = "▏"; + + pub struct Set { + pub full: &'static str, + pub seven_eighths: &'static str, + pub three_quarters: &'static str, + pub five_eighths: &'static str, + pub half: &'static str, + pub three_eighths: &'static str, + pub one_quarter: &'static str, + pub one_eighth: &'static str, + pub empty: &'static str, + } + + pub const THREE_LEVELS: Set = Set { + full: FULL, + seven_eighths: FULL, + three_quarters: HALF, + five_eighths: HALF, + half: HALF, + three_eighths: HALF, + one_quarter: HALF, + one_eighth: " ", + empty: " ", + }; + + pub const NINE_LEVELS: Set = Set { + full: FULL, + seven_eighths: SEVEN_EIGHTHS, + three_quarters: THREE_QUARTERS, + five_eighths: FIVE_EIGHTHS, + half: HALF, + three_eighths: THREE_EIGHTHS, + one_quarter: ONE_QUARTER, + one_eighth: ONE_EIGHTH, + empty: " ", + }; } pub mod bar { @@ -18,6 +54,42 @@ pub mod bar { pub const THREE_EIGHTHS: &str = "▃"; pub const ONE_QUARTER: &str = "▂"; pub const ONE_EIGHTH: &str = "▁"; + + pub struct Set { + pub full: &'static str, + pub seven_eighths: &'static str, + pub three_quarters: &'static str, + pub five_eighths: &'static str, + pub half: &'static str, + pub three_eighths: &'static str, + pub one_quarter: &'static str, + pub one_eighth: &'static str, + pub empty: &'static str, + } + + pub const THREE_LEVELS: Set = Set { + full: FULL, + seven_eighths: FULL, + three_quarters: HALF, + five_eighths: HALF, + half: HALF, + three_eighths: HALF, + one_quarter: HALF, + one_eighth: " ", + empty: " ", + }; + + pub const NINE_LEVELS: Set = Set { + full: FULL, + seven_eighths: SEVEN_EIGHTHS, + three_quarters: THREE_QUARTERS, + five_eighths: FIVE_EIGHTHS, + half: HALF, + three_eighths: THREE_EIGHTHS, + one_quarter: ONE_QUARTER, + one_eighth: ONE_EIGHTH, + empty: " ", + }; } pub mod line { diff --git a/src/widgets/barchart.rs b/src/widgets/barchart.rs index d38e750..5b86d05 100644 --- a/src/widgets/barchart.rs +++ b/src/widgets/barchart.rs @@ -1,13 +1,13 @@ +use crate::{ + buffer::Buffer, + layout::Rect, + style::Style, + symbols, + widgets::{Block, Widget}, +}; use std::cmp::{max, min}; - use unicode_width::UnicodeWidthStr; -use crate::buffer::Buffer; -use crate::layout::Rect; -use crate::style::Style; -use crate::symbols::bar; -use crate::widgets::{Block, Widget}; - /// Display multiple bars in a single widgets /// /// # Examples @@ -32,6 +32,8 @@ pub struct BarChart<'a> { bar_width: u16, /// The gap between each bar bar_gap: u16, + /// Set of symbols used to display the data + bar_set: symbols::bar::Set, /// Style of the values printed at the bottom of each bar value_style: Style, /// Style of the labels printed under each bar @@ -56,6 +58,7 @@ impl<'a> Default for BarChart<'a> { values: Vec::new(), bar_width: 1, bar_gap: 1, + bar_set: symbols::bar::NINE_LEVELS, value_style: Default::default(), label_style: Default::default(), style: Default::default(), @@ -77,6 +80,7 @@ impl<'a> BarChart<'a> { self.block = Some(block); self } + pub fn max(mut self, max: u64) -> BarChart<'a> { self.max = Some(max); self @@ -86,18 +90,27 @@ impl<'a> BarChart<'a> { self.bar_width = width; self } + pub fn bar_gap(mut self, gap: u16) -> BarChart<'a> { self.bar_gap = gap; self } + + pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> BarChart<'a> { + self.bar_set = bar_set; + self + } + pub fn value_style(mut self, style: Style) -> BarChart<'a> { self.value_style = style; self } + pub fn label_style(mut self, style: Style) -> BarChart<'a> { self.label_style = style; self } + pub fn style(mut self, style: Style) -> BarChart<'a> { self.style = style; self @@ -141,15 +154,15 @@ impl<'a> Widget for BarChart<'a> { for j in (0..chart_area.height - 1).rev() { for (i, d) in data.iter_mut().enumerate() { let symbol = match d.1 { - 0 => " ", - 1 => bar::ONE_EIGHTH, - 2 => bar::ONE_QUARTER, - 3 => bar::THREE_EIGHTHS, - 4 => bar::HALF, - 5 => bar::FIVE_EIGHTHS, - 6 => bar::THREE_QUARTERS, - 7 => bar::SEVEN_EIGHTHS, - _ => bar::FULL, + 0 => self.bar_set.empty, + 1 => self.bar_set.one_eighth, + 2 => self.bar_set.one_quarter, + 3 => self.bar_set.three_eighths, + 4 => self.bar_set.half, + 5 => self.bar_set.five_eighths, + 6 => self.bar_set.three_quarters, + 7 => self.bar_set.seven_eighths, + _ => self.bar_set.full, }; for x in 0..self.bar_width { diff --git a/src/widgets/sparkline.rs b/src/widgets/sparkline.rs index c724b2f..71987a2 100644 --- a/src/widgets/sparkline.rs +++ b/src/widgets/sparkline.rs @@ -1,11 +1,12 @@ +use crate::{ + buffer::Buffer, + layout::Rect, + style::Style, + symbols, + widgets::{Block, Widget}, +}; use std::cmp::min; -use crate::buffer::Buffer; -use crate::layout::Rect; -use crate::style::Style; -use crate::symbols::bar; -use crate::widgets::{Block, Widget}; - /// Widget to render a sparkline over one or more lines. /// /// # Examples @@ -29,6 +30,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, + /// A set of bar symbols used to represent the give data + bar_set: symbols::bar::Set, } impl<'a> Default for Sparkline<'a> { @@ -38,6 +41,7 @@ impl<'a> Default for Sparkline<'a> { style: Default::default(), data: &[], max: None, + bar_set: symbols::bar::NINE_LEVELS, } } } @@ -62,6 +66,11 @@ impl<'a> Sparkline<'a> { self.max = Some(max); self } + + pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> Sparkline<'a> { + self.bar_set = bar_set; + self + } } impl<'a> Widget for Sparkline<'a> { @@ -98,15 +107,15 @@ 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 => " ", - 1 => bar::ONE_EIGHTH, - 2 => bar::ONE_QUARTER, - 3 => bar::THREE_EIGHTHS, - 4 => bar::HALF, - 5 => bar::FIVE_EIGHTHS, - 6 => bar::THREE_QUARTERS, - 7 => bar::SEVEN_EIGHTHS, - _ => bar::FULL, + 0 => self.bar_set.empty, + 1 => self.bar_set.one_eighth, + 2 => self.bar_set.one_quarter, + 3 => self.bar_set.three_eighths, + 4 => self.bar_set.half, + 5 => self.bar_set.five_eighths, + 6 => self.bar_set.three_quarters, + 7 => self.bar_set.seven_eighths, + _ => self.bar_set.full, }; buf.get_mut(spark_area.left() + i as u16, spark_area.top() + j) .set_symbol(symbol)