plotters_unsable/chart/
mesh.rs

1use std::marker::PhantomData;
2
3use super::context::ChartContext;
4use crate::coord::{MeshLine, Ranged, RangedCoord};
5use crate::drawing::backend::DrawingBackend;
6use crate::drawing::DrawingAreaErrorKind;
7use crate::style::{FontDesc, Mixable, RGBColor, ShapeStyle, TextStyle};
8
9/// The struct that is used for tracking the configuration of a mesh of any chart
10pub struct MeshStyle<'a, X: Ranged, Y: Ranged, DB>
11where
12    DB: DrawingBackend,
13{
14    pub(super) draw_x_mesh: bool,
15    pub(super) draw_y_mesh: bool,
16    pub(super) draw_x_axis: bool,
17    pub(super) draw_y_axis: bool,
18    pub(super) x_label_offset: i32,
19    pub(super) n_x_labels: usize,
20    pub(super) n_y_labels: usize,
21    pub(super) axis_desc_style: Option<TextStyle<'a>>,
22    pub(super) x_desc: Option<String>,
23    pub(super) y_desc: Option<String>,
24    pub(super) line_style_1: Option<ShapeStyle<'a>>,
25    pub(super) line_style_2: Option<ShapeStyle<'a>>,
26    pub(super) axis_style: Option<ShapeStyle<'a>>,
27    pub(super) label_style: Option<TextStyle<'a>>,
28    pub(super) format_x: &'a dyn Fn(&X::ValueType) -> String,
29    pub(super) format_y: &'a dyn Fn(&Y::ValueType) -> String,
30    pub(super) target: Option<&'a mut ChartContext<DB, RangedCoord<X, Y>>>,
31    pub(super) _pahtom_data: PhantomData<(X, Y)>,
32}
33
34impl<'a, X, Y, DB> MeshStyle<'a, X, Y, DB>
35where
36    X: Ranged,
37    Y: Ranged,
38    DB: DrawingBackend,
39{
40    /// The offset of x labels. This is used when we want to place the label in the middle of
41    /// the grid. This is useful if we are drawing a histogram
42    /// - `value`: The offset in pixel
43    pub fn x_label_offset(&mut self, value: i32) -> &mut Self {
44        self.x_label_offset = value;
45        self
46    }
47
48    /// Disable the mesh for the x axis.
49    pub fn disable_x_mesh(&mut self) -> &mut Self {
50        self.draw_x_mesh = false;
51        self
52    }
53
54    /// Disable the mesh for the y axis
55    pub fn disable_y_mesh(&mut self) -> &mut Self {
56        self.draw_y_mesh = false;
57        self
58    }
59
60    /// Disable drawing the X axis
61    pub fn disable_x_axis(&mut self) -> &mut Self {
62        self.draw_x_axis = false;
63        self
64    }
65
66    /// Disable drawing the Y axis
67    pub fn disable_y_axis(&mut self) -> &mut Self {
68        self.draw_y_axis = false;
69        self
70    }
71
72    /// Set the style definition for the axis
73    /// - `style`: The style for the axis
74    pub fn axis_style<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
75        self.axis_style = Some(style.into());
76        self
77    }
78    /// Set how many labels for the X axis at most
79    /// - `value`: The maximum desired number of labels in the X axis
80    pub fn x_labels(&mut self, value: usize) -> &mut Self {
81        self.n_x_labels = value;
82        self
83    }
84
85    /// Set how many label for the Y axis at most
86    /// - `value`: The maximum desired number of labels in the Y axis
87    pub fn y_labels(&mut self, value: usize) -> &mut Self {
88        self.n_y_labels = value;
89        self
90    }
91
92    /// Set the style for the coarse grind grid
93    /// - `style`: This is the fcoarse grind grid style
94    pub fn line_style_1<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
95        self.line_style_1 = Some(style.into());
96        self
97    }
98
99    /// Set the style for the fine grind grid
100    /// - `style`: The fine grind grid style
101    pub fn line_style_2<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
102        self.line_style_2 = Some(style.into());
103        self
104    }
105
106    /// Set the style of the label text
107    /// - `style`: The text style that would be applied to the labels
108    pub fn label_style<T: Into<TextStyle<'a>>>(&mut self, style: T) -> &mut Self {
109        self.label_style = Some(style.into());
110        self
111    }
112
113    /// Set the formatter function for the X label text
114    /// - `fmt`: The formatter function
115    pub fn x_label_formatter(&mut self, fmt: &'a dyn Fn(&X::ValueType) -> String) -> &mut Self {
116        self.format_x = fmt;
117        self
118    }
119
120    /// Set the formatter function for the Y label text
121    /// - `fmt`: The formatter function
122    pub fn y_label_formatter(&mut self, fmt: &'a dyn Fn(&Y::ValueType) -> String) -> &mut Self {
123        self.format_y = fmt;
124        self
125    }
126
127    /// Set the axis description's style. If not given, use label style instead.
128    /// - `style`: The text style that would be applied to descriptions
129    pub fn axis_desc_style<T: Into<TextStyle<'a>>>(&mut self, style: T) -> &mut Self {
130        self.axis_desc_style = Some(style.into());
131        self
132    }
133
134    /// Set the X axis's description
135    /// - `desc`: The description of the X axis
136    pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
137        self.x_desc = Some(desc.into());
138        self
139    }
140
141    /// Set the Y axis's description
142    /// - `desc`: The description of the Y axis
143    pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
144        self.y_desc = Some(desc.into());
145        self
146    }
147
148    /// Draw the configured mesh on the target plot
149    pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
150        let mut target = None;
151        std::mem::swap(&mut target, &mut self.target);
152        let target = target.unwrap();
153
154        let default_mesh_color_1 = RGBColor(0, 0, 0).mix(0.2);
155        let default_mesh_color_2 = RGBColor(0, 0, 0).mix(0.1);
156        let default_axis_color = RGBColor(0, 0, 0);
157        let default_label_font = FontDesc::new("Arial", 12.0);
158
159        let mesh_style_1 = self
160            .line_style_1
161            .clone()
162            .unwrap_or_else(|| (&default_mesh_color_1).into());
163        let mesh_style_2 = self
164            .line_style_2
165            .clone()
166            .unwrap_or_else(|| (&default_mesh_color_2).into());
167        let axis_style = self
168            .axis_style
169            .clone()
170            .unwrap_or_else(|| (&default_axis_color).into());
171
172        let label_style =
173            unsafe { std::mem::transmute::<_, Option<TextStyle>>(self.label_style.clone()) }
174                .unwrap_or_else(|| (&default_label_font).into());
175
176        let axis_desc_style =
177            unsafe { std::mem::transmute::<_, Option<TextStyle>>(self.axis_desc_style.clone()) }
178                .unwrap_or_else(|| label_style.clone());
179
180        target.draw_mesh(
181            (self.n_y_labels * 10, self.n_x_labels * 10),
182            &mesh_style_2,
183            &label_style,
184            |_| None,
185            self.draw_x_mesh,
186            self.draw_y_mesh,
187            self.x_label_offset,
188            false,
189            false,
190            &axis_style,
191            &axis_desc_style,
192            self.x_desc.clone(),
193            self.y_desc.clone(),
194        )?;
195
196        target.draw_mesh(
197            (self.n_y_labels, self.n_x_labels),
198            &mesh_style_1,
199            &label_style,
200            |m| match m {
201                MeshLine::XMesh(_, _, v) => Some((self.format_x)(v)),
202                MeshLine::YMesh(_, _, v) => Some((self.format_y)(v)),
203            },
204            self.draw_x_mesh,
205            self.draw_y_mesh,
206            self.x_label_offset,
207            self.draw_x_axis,
208            self.draw_y_axis,
209            &axis_style,
210            &axis_desc_style,
211            None,
212            None,
213        )
214    }
215}