leptos_chartistry/layout/
mod.rs

1mod compose;
2pub mod legend;
3pub mod rotated_label;
4pub mod tick_labels;
5
6pub use compose::Layout;
7
8use crate::{
9    bounds::Bounds,
10    edge::Edge,
11    state::{PreState, State},
12    Tick,
13};
14use leptos::prelude::*;
15
16/// All possible layout options for an edge of a [Chart](crate::Chart). See [IntoEdge](trait@IntoEdge) for details.
17#[derive(Clone)]
18#[non_exhaustive]
19pub enum EdgeLayout<XY: Tick> {
20    /// Legend. See [legend](struct@legend::Legend) for details.
21    Legend(legend::Legend),
22    /// Rotated label. See [rotated_label](struct@rotated_label::RotatedLabel) for details.
23    RotatedLabel(rotated_label::RotatedLabel),
24    /// Tick labels. See [tick_labels](struct@tick_labels::TickLabels) for details.
25    TickLabels(tick_labels::TickLabels<XY>),
26}
27
28struct UseVerticalLayout {
29    width: Signal<f64>,
30    layout: UseLayout,
31}
32
33#[derive(Clone)]
34enum UseLayout {
35    Legend(legend::Legend),
36    RotatedLabel(rotated_label::RotatedLabel),
37    TickLabels(tick_labels::UseTickLabels),
38}
39
40impl UseLayout {
41    fn render<X: Tick, Y: Tick>(
42        self,
43        edge: Edge,
44        bounds: Memo<Bounds>,
45        state: State<X, Y>,
46    ) -> impl IntoView {
47        match self {
48            Self::Legend(inner) => view! {<legend::Legend legend=inner edge=edge bounds=bounds state=state />}.into_any(),
49            Self::RotatedLabel(inner) => view! {<rotated_label::RotatedLabel label=inner edge=edge bounds=bounds state=state />}.into_any(),
50            Self::TickLabels(inner) => view! {<tick_labels::TickLabels ticks=inner edge=edge bounds=bounds state=state />}.into_any(),
51        }
52    }
53}
54
55impl<X: Tick> EdgeLayout<X> {
56    fn fixed_height<Y: Tick>(&self, state: &PreState<X, Y>) -> Signal<f64> {
57        match self {
58            Self::Legend(inner) => inner.fixed_height(state),
59            Self::RotatedLabel(inner) => inner.fixed_height(state),
60            Self::TickLabels(inner) => inner.fixed_height(state),
61        }
62    }
63
64    fn to_horizontal_use<Y: Tick>(
65        &self,
66        state: &PreState<X, Y>,
67        avail_width: Memo<f64>,
68    ) -> UseLayout {
69        match self {
70            Self::Legend(inner) => inner.to_horizontal_use(),
71            Self::RotatedLabel(inner) => inner.to_horizontal_use(),
72            Self::TickLabels(inner) => inner.to_horizontal_use(state, avail_width),
73        }
74    }
75}
76
77impl<Y: Tick> EdgeLayout<Y> {
78    fn to_vertical_use<X: Tick>(
79        &self,
80        state: &PreState<X, Y>,
81        avail_height: Memo<f64>,
82    ) -> UseVerticalLayout {
83        match self {
84            Self::Legend(inner) => inner.to_vertical_use(state),
85            Self::RotatedLabel(inner) => inner.to_vertical_use(state),
86            Self::TickLabels(inner) => inner.to_vertical_use(state, avail_height),
87        }
88    }
89}
90
91/// Convert a type (e.g., a [rotated label](struct@rotated_label::RotatedLabel)) into an edge layout for use with [Chart](crate::Chart).
92pub trait IntoEdge<XY: Tick> {
93    /// Create an edge layout from the type. See [IntoEdge](trait@IntoEdge) for details.
94    fn into_edge(self) -> EdgeLayout<XY>;
95}
96
97macro_rules! impl_into_edge {
98    ($ty:ty, $enum:ident) => {
99        impl<XY: Tick> IntoEdge<XY> for $ty {
100            fn into_edge(self) -> EdgeLayout<XY> {
101                EdgeLayout::$enum(self)
102            }
103        }
104
105        impl<XY: Tick> From<$ty> for EdgeLayout<XY> {
106            fn from(inner: $ty) -> Self {
107                inner.into_edge()
108            }
109        }
110
111        impl<XY: Tick> From<$ty> for Vec<EdgeLayout<XY>> {
112            fn from(inner: $ty) -> Self {
113                vec![inner.into_edge()]
114            }
115        }
116    };
117}
118impl_into_edge!(legend::Legend, Legend);
119impl_into_edge!(rotated_label::RotatedLabel, RotatedLabel);
120impl_into_edge!(tick_labels::TickLabels<XY>, TickLabels);