use std::fmt::Display;
use plotters::{
series::AreaSeries,
style::{Color, FontTransform, IntoFont, ShapeStyle, TextStyle},
};
use rust_decimal::prelude::ToPrimitive;
use crate::app::message::Message;
use super::{Duration, account::transactions::Transactions, solarized};
pub struct Chart<T: Clone + Display> {
pub txs: Transactions<T>,
pub duration: Duration,
}
impl<T: Clone + Display> plotters_iced2::Chart<Message> for Chart<T> {
type State = ();
fn build_chart<DB: plotters::prelude::DrawingBackend>(
&self,
_state: &Self::State,
mut chart: plotters::prelude::ChartBuilder<DB>,
) {
let txs = match self.duration {
Duration::Week => self.txs.last_week(),
Duration::Month => self.txs.last_month(),
Duration::Year => self.txs.last_year(),
Duration::All => self.txs.clone(),
};
if let (Some(Some(min_balance)), Some(Some(max_balance)), Some(min_date), Some(max_date)) = (
txs.min_balance().map(|min| min.to_f32()),
txs.max_balance().map(|max| max.to_f32()),
txs.min_date(),
txs.max_date(),
) {
let mut chart = chart
.caption(
format!("Total in {}", self.txs.currency),
TextStyle::from(("sans-serif", 20).into_font()),
)
.x_label_area_size(28)
.y_label_area_size(28)
.margin_top(20)
.margin_bottom(30)
.margin_left(60)
.margin_right(60)
.build_cartesian_2d(min_date..max_date, min_balance..max_balance)
.expect("failed to build chart");
chart
.configure_mesh()
.bold_line_style(solarized::plot::base0())
.light_line_style(solarized::plot::base1().mix(0.25))
.axis_style(ShapeStyle::from(solarized::plot::base0()).stroke_width(1))
.x_labels(10)
.x_label_style(
("sans-serif", 15)
.into_font()
.color(&solarized::plot::base0()),
)
.x_label_formatter(&|y| y.format("%Y-%m-%d %Z").to_string())
.y_labels(10)
.y_label_style(
("sans-serif", 15)
.into_font()
.color(&solarized::plot::base0())
.transform(FontTransform::Rotate90),
)
.y_label_formatter(&thousands::Separable::separate_with_underscores)
.draw()
.expect("failed to draw chart mesh");
chart
.draw_series(
AreaSeries::new(
txs.txs
.iter()
.map(|tx| (tx.date, tx.balance.to_f32().unwrap())),
0.0,
solarized::plot::blue(),
)
.border_style(ShapeStyle::from(solarized::plot::blue()).stroke_width(2)),
)
.expect("failed to draw chart data");
}
}
}