use serde::{Deserialize, Serialize};
use crate::layout::Direction;
use crate::node::{ActionId, Common, IntoNode, Node};
use crate::style::Style;
use crate::text::Line;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Bar {
pub value: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label: Option<Line>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_value: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub style: Option<Style>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value_style: Option<Style>,
}
impl Bar {
#[must_use]
pub fn new(value: u64) -> Self {
Self {
value,
label: None,
text_value: None,
style: None,
value_style: None,
}
}
#[must_use]
pub fn label(mut self, label: impl Into<Line>) -> Self {
self.label = Some(label.into());
self
}
#[must_use]
pub fn text_value(mut self, text: impl Into<String>) -> Self {
self.text_value = Some(text.into());
self
}
#[must_use]
pub fn style(mut self, style: Style) -> Self {
self.style = Some(style);
self
}
#[must_use]
pub fn value_style(mut self, style: Style) -> Self {
self.value_style = Some(style);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BarGroup {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label: Option<Line>,
pub bars: Vec<Bar>,
}
impl BarGroup {
#[must_use]
pub fn new(bars: impl IntoIterator<Item = Bar>) -> Self {
Self {
label: None,
bars: bars.into_iter().collect(),
}
}
#[must_use]
pub fn label(mut self, label: impl Into<Line>) -> Self {
self.label = Some(label.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BarChart {
#[serde(flatten)]
pub common: Common,
pub data: Vec<BarGroup>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bar_width: Option<u16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bar_gap: Option<u16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub group_gap: Option<u16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub direction: Option<Direction>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bar_style: Option<Style>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value_style: Option<Style>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label_style: Option<Style>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub on_select: Option<ActionId>,
}
impl BarChart {
#[must_use]
pub fn new(data: impl IntoIterator<Item = BarGroup>) -> Self {
Self {
data: data.into_iter().collect(),
..Self::default()
}
}
#[must_use]
pub fn from_pairs(pairs: impl IntoIterator<Item = (impl Into<Line>, u64)>) -> Self {
Self::new(vec![BarGroup::new(
pairs
.into_iter()
.map(|(label, value)| Bar::new(value).label(label)),
)])
}
#[must_use]
pub fn bar_width(mut self, width: u16) -> Self {
self.bar_width = Some(width);
self
}
#[must_use]
pub fn bar_gap(mut self, gap: u16) -> Self {
self.bar_gap = Some(gap);
self
}
#[must_use]
pub fn group_gap(mut self, gap: u16) -> Self {
self.group_gap = Some(gap);
self
}
#[must_use]
pub fn direction(mut self, direction: Direction) -> Self {
self.direction = Some(direction);
self
}
#[must_use]
pub fn max(mut self, max: u64) -> Self {
self.max = Some(max);
self
}
#[must_use]
pub fn bar_style(mut self, style: Style) -> Self {
self.bar_style = Some(style);
self
}
#[must_use]
pub fn value_style(mut self, style: Style) -> Self {
self.value_style = Some(style);
self
}
#[must_use]
pub fn label_style(mut self, style: Style) -> Self {
self.label_style = Some(style);
self
}
#[must_use]
pub fn on_select(mut self, action: impl Into<ActionId>) -> Self {
self.on_select = Some(action.into());
self
}
}
impl IntoNode for BarChart {}
impl From<BarChart> for Node {
fn from(c: BarChart) -> Self {
Node::BarChart(c)
}
}