leptos_chartistry/series/
stack.rs1use super::{ApplyUseSeries, GetYValue, IntoUseLine, SeriesAcc, UseY};
2use crate::{
3 colours::{Colour, ColourScheme, BATLOW},
4 Line,
5};
6use leptos::prelude::*;
7use std::sync::Arc;
8
9pub const STACK_COLOUR_SCHEME: [Colour; 10] = BATLOW;
11
12#[derive(Clone)]
24#[non_exhaustive]
25pub struct Stack<T, Y> {
26 lines: Vec<Line<T, Y>>,
27 pub colours: RwSignal<ColourScheme>,
29}
30
31impl<T, Y> Stack<T, Y> {
32 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn line(mut self, line: impl Into<Line<T, Y>>) -> Self {
39 self.lines.push(line.into());
40 self
41 }
42
43 pub fn len(&self) -> usize {
45 self.lines.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.lines.is_empty()
51 }
52
53 pub fn with_colours<Opt>(self, colours: impl Into<ColourScheme>) -> Self {
55 self.colours.set(colours.into());
56 self
57 }
58}
59
60impl<T, Y> Default for Stack<T, Y> {
61 fn default() -> Self {
62 Self {
63 lines: Vec::new(),
64 colours: RwSignal::new(ColourScheme::from(STACK_COLOUR_SCHEME).invert()),
65 }
66 }
67}
68
69impl<T, Y, I: IntoIterator<Item = Line<T, Y>>> From<I> for Stack<T, Y> {
70 fn from(lines: I) -> Self {
71 let mut stack = Self::default();
72 for line in lines {
73 stack = stack.line(line);
74 }
75 stack
76 }
77}
78
79impl<T: 'static> ApplyUseSeries<T, f64> for Stack<T, f64> {
80 fn apply_use_series(self: Arc<Self>, series: &mut SeriesAcc<T, f64>) {
81 let colours = self.colours;
82 let total_lines = self.lines.len();
83 let mut previous = Vec::with_capacity(total_lines);
84 for (id, line) in self.lines.clone().into_iter().enumerate() {
85 let colour = Memo::new(move |_| colours.get().interpolate(id, total_lines));
86 let line = StackedLine {
87 line,
88 previous: previous.clone(),
89 };
90 let get_y = series.push_line(colour, line);
92 previous.push(get_y);
94 }
95 }
96}
97
98#[derive(Clone)]
99struct StackedLine<T, Y> {
100 line: Line<T, Y>,
101 previous: Vec<Arc<dyn GetYValue<T, Y>>>,
102}
103
104#[derive(Clone)]
105struct UseStackLine<T, Y> {
106 line: Arc<dyn GetYValue<T, Y>>,
107 previous: Vec<Arc<dyn GetYValue<T, Y>>>,
108}
109
110impl<T: 'static> IntoUseLine<T, f64> for StackedLine<T, f64> {
111 fn into_use_line(self, id: usize, colour: Memo<Colour>) -> (UseY, Arc<dyn GetYValue<T, f64>>) {
112 let (line, get_y) = self.line.into_use_line(id, colour);
113 let get_y = Arc::new(UseStackLine {
114 line: get_y,
115 previous: self.previous.clone(),
116 });
117 (line, get_y)
118 }
119}
120
121impl<T> GetYValue<T, f64> for UseStackLine<T, f64> {
122 fn value(&self, t: &T) -> f64 {
123 self.line.value(t)
124 }
125
126 fn stacked_value(&self, t: &T) -> f64 {
127 self.previous
128 .iter()
129 .chain(std::iter::once(&self.line))
130 .map(|get_y| get_y.value(t))
131 .filter(|v| v.is_normal())
132 .sum()
133 }
134}