• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::marker::PhantomData;
2 
3 use super::ChartContext;
4 use crate::coord::cartesian::Cartesian3d;
5 use crate::coord::ranged1d::{BoldPoints, LightPoints, Ranged, ValueFormatter};
6 use crate::style::colors::{BLACK, TRANSPARENT};
7 use crate::style::Color;
8 use crate::style::{AsRelative, ShapeStyle, SizeDesc, TextStyle};
9 
10 use super::Coord3D;
11 
12 use crate::drawing::DrawingAreaErrorKind;
13 
14 use plotters_backend::DrawingBackend;
15 
16 /**
17 Implements 3D plot axes configurations.
18 
19 The best way to use this struct is by way of the [`configure_axes()`] function.
20 See [`ChartContext::configure_axes()`] for more information and examples.
21 */
22 pub struct Axes3dStyle<'a, 'b, X: Ranged, Y: Ranged, Z: Ranged, DB: DrawingBackend> {
23     pub(super) parent_size: (u32, u32),
24     pub(super) target: Option<&'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>>,
25     pub(super) tick_size: i32,
26     pub(super) light_lines_limit: [usize; 3],
27     pub(super) n_labels: [usize; 3],
28     pub(super) bold_line_style: ShapeStyle,
29     pub(super) light_line_style: ShapeStyle,
30     pub(super) axis_panel_style: ShapeStyle,
31     pub(super) axis_style: ShapeStyle,
32     pub(super) label_style: TextStyle<'b>,
33     pub(super) format_x: &'b dyn Fn(&X::ValueType) -> String,
34     pub(super) format_y: &'b dyn Fn(&Y::ValueType) -> String,
35     pub(super) format_z: &'b dyn Fn(&Z::ValueType) -> String,
36     _phantom: PhantomData<&'a (X, Y, Z)>,
37 }
38 
39 impl<'a, 'b, X, Y, Z, XT, YT, ZT, DB> Axes3dStyle<'a, 'b, X, Y, Z, DB>
40 where
41     X: Ranged<ValueType = XT> + ValueFormatter<XT>,
42     Y: Ranged<ValueType = YT> + ValueFormatter<YT>,
43     Z: Ranged<ValueType = ZT> + ValueFormatter<ZT>,
44     DB: DrawingBackend,
45 {
46     /**
47     Set the size of the tick marks.
48 
49     - `value` Desired tick mark size, in pixels.
50 
51     See [`ChartContext::configure_axes()`] for more information and examples.
52     */
tick_size<Size: SizeDesc>(&mut self, size: Size) -> &mut Self53     pub fn tick_size<Size: SizeDesc>(&mut self, size: Size) -> &mut Self {
54         let actual_size = size.in_pixels(&self.parent_size);
55         self.tick_size = actual_size;
56         self
57     }
58 
59     /**
60     Set the maximum number of divisions for the minor grid in the X axis.
61 
62     - `value`: Maximum desired divisions between two consecutive X labels.
63 
64     See [`ChartContext::configure_axes()`] for more information and examples.
65     */
x_max_light_lines(&mut self, value: usize) -> &mut Self66     pub fn x_max_light_lines(&mut self, value: usize) -> &mut Self {
67         self.light_lines_limit[0] = value;
68         self
69     }
70 
71     /**
72     Set the maximum number of divisions for the minor grid in the Y axis.
73 
74     - `value`: Maximum desired divisions between two consecutive Y labels.
75 
76     See [`ChartContext::configure_axes()`] for more information and examples.
77     */
y_max_light_lines(&mut self, value: usize) -> &mut Self78     pub fn y_max_light_lines(&mut self, value: usize) -> &mut Self {
79         self.light_lines_limit[1] = value;
80         self
81     }
82 
83     /**
84     Set the maximum number of divisions for the minor grid in the Z axis.
85 
86     - `value`: Maximum desired divisions between two consecutive Z labels.
87 
88     See [`ChartContext::configure_axes()`] for more information and examples.
89     */
z_max_light_lines(&mut self, value: usize) -> &mut Self90     pub fn z_max_light_lines(&mut self, value: usize) -> &mut Self {
91         self.light_lines_limit[2] = value;
92         self
93     }
94 
95     /**
96     Set the maximum number of divisions for the minor grid.
97 
98     - `value`: Maximum desired divisions between two consecutive labels in X, Y, and Z.
99 
100     See [`ChartContext::configure_axes()`] for more information and examples.
101     */
max_light_lines(&mut self, value: usize) -> &mut Self102     pub fn max_light_lines(&mut self, value: usize) -> &mut Self {
103         self.light_lines_limit[0] = value;
104         self.light_lines_limit[1] = value;
105         self.light_lines_limit[2] = value;
106         self
107     }
108 
109     /**
110     Set the number of labels on the X axes.
111 
112     See [`ChartContext::configure_axes()`] for more information and examples.
113     */
x_labels(&mut self, n: usize) -> &mut Self114     pub fn x_labels(&mut self, n: usize) -> &mut Self {
115         self.n_labels[0] = n;
116         self
117     }
118 
119     /**
120     Set the number of labels on the Y axes.
121 
122     See [`ChartContext::configure_axes()`] for more information and examples.
123     */
y_labels(&mut self, n: usize) -> &mut Self124     pub fn y_labels(&mut self, n: usize) -> &mut Self {
125         self.n_labels[1] = n;
126         self
127     }
128 
129     /**
130     Set the number of labels on the Z axes.
131 
132     See [`ChartContext::configure_axes()`] for more information and examples.
133     */
z_labels(&mut self, n: usize) -> &mut Self134     pub fn z_labels(&mut self, n: usize) -> &mut Self {
135         self.n_labels[2] = n;
136         self
137     }
138 
139     /**
140     Sets the style of the panels in the background.
141 
142     See [`ChartContext::configure_axes()`] for more information and examples.
143     */
axis_panel_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self144     pub fn axis_panel_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
145         self.axis_panel_style = style.into();
146         self
147     }
148 
149     /**
150     Sets the style of the major grid lines.
151 
152     See [`ChartContext::configure_axes()`] for more information and examples.
153     */
bold_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self154     pub fn bold_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
155         self.bold_line_style = style.into();
156         self
157     }
158 
159     /**
160     Sets the style of the minor grid lines.
161 
162     See [`ChartContext::configure_axes()`] for more information and examples.
163     */
light_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self164     pub fn light_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
165         self.light_line_style = style.into();
166         self
167     }
168 
169     /**
170     Sets the text style of the axis labels.
171 
172     See [`ChartContext::configure_axes()`] for more information and examples.
173     */
label_style<S: Into<TextStyle<'b>>>(&mut self, style: S) -> &mut Self174     pub fn label_style<S: Into<TextStyle<'b>>>(&mut self, style: S) -> &mut Self {
175         self.label_style = style.into();
176         self
177     }
178 
179     /**
180     Specifies the string format of the X axis labels.
181 
182     See [`ChartContext::configure_axes()`] for more information and examples.
183     */
x_formatter<F: Fn(&X::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self184     pub fn x_formatter<F: Fn(&X::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
185         self.format_x = f;
186         self
187     }
188 
189     /**
190     Specifies the string format of the Y axis labels.
191 
192     See [`ChartContext::configure_axes()`] for more information and examples.
193     */
y_formatter<F: Fn(&Y::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self194     pub fn y_formatter<F: Fn(&Y::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
195         self.format_y = f;
196         self
197     }
198 
199     /**
200     Specifies the string format of the Z axis labels.
201 
202     See [`ChartContext::configure_axes()`] for more information and examples.
203     */
z_formatter<F: Fn(&Z::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self204     pub fn z_formatter<F: Fn(&Z::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
205         self.format_z = f;
206         self
207     }
208 
209     /**
210     Constructs a new configuration object and defines the defaults.
211 
212     This is used internally by Plotters and should probably not be included in user code.
213     See [`ChartContext::configure_axes()`] for more information and examples.
214     */
new(chart: &'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>) -> Self215     pub(crate) fn new(chart: &'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>) -> Self {
216         let parent_size = chart.drawing_area.dim_in_pixel();
217         let base_tick_size = (5u32).percent().max(5).in_pixels(chart.plotting_area());
218         let tick_size = base_tick_size;
219         Self {
220             parent_size,
221             tick_size,
222             light_lines_limit: [10, 10, 10],
223             n_labels: [10, 10, 10],
224             bold_line_style: Into::<ShapeStyle>::into(&BLACK.mix(0.2)),
225             light_line_style: Into::<ShapeStyle>::into(&TRANSPARENT),
226             axis_panel_style: Into::<ShapeStyle>::into(&BLACK.mix(0.1)),
227             axis_style: Into::<ShapeStyle>::into(&BLACK.mix(0.8)),
228             label_style: ("sans-serif", (12).percent().max(12).in_pixels(&parent_size)).into(),
229             format_x: &X::format,
230             format_y: &Y::format,
231             format_z: &Z::format,
232             _phantom: PhantomData,
233             target: Some(chart),
234         }
235     }
236 
draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> where XT: Clone, YT: Clone, ZT: Clone,237     pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>>
238     where
239         XT: Clone,
240         YT: Clone,
241         ZT: Clone,
242     {
243         let chart = self.target.take().unwrap();
244         let kps_bold = chart.get_key_points(
245             BoldPoints(self.n_labels[0]),
246             BoldPoints(self.n_labels[1]),
247             BoldPoints(self.n_labels[2]),
248         );
249         let kps_light = chart.get_key_points(
250             LightPoints::new(
251                 self.n_labels[0],
252                 self.n_labels[0] * self.light_lines_limit[0],
253             ),
254             LightPoints::new(
255                 self.n_labels[1],
256                 self.n_labels[1] * self.light_lines_limit[1],
257             ),
258             LightPoints::new(
259                 self.n_labels[2],
260                 self.n_labels[2] * self.light_lines_limit[2],
261             ),
262         );
263 
264         let panels = chart.draw_axis_panels(
265             &kps_bold,
266             &kps_light,
267             self.axis_panel_style,
268             self.bold_line_style,
269             self.light_line_style,
270         )?;
271 
272         for i in 0..3 {
273             let axis = chart.draw_axis(i, &panels, self.axis_style)?;
274             let labels: Vec<_> = match i {
275                 0 => kps_bold
276                     .x_points
277                     .iter()
278                     .map(|x| {
279                         let x_text = (self.format_x)(x);
280                         let mut p = axis[0].clone();
281                         p[0] = Coord3D::X(x.clone());
282                         (p, x_text)
283                     })
284                     .collect(),
285                 1 => kps_bold
286                     .y_points
287                     .iter()
288                     .map(|y| {
289                         let y_text = (self.format_y)(y);
290                         let mut p = axis[0].clone();
291                         p[1] = Coord3D::Y(y.clone());
292                         (p, y_text)
293                     })
294                     .collect(),
295                 _ => kps_bold
296                     .z_points
297                     .iter()
298                     .map(|z| {
299                         let z_text = (self.format_z)(z);
300                         let mut p = axis[0].clone();
301                         p[2] = Coord3D::Z(z.clone());
302                         (p, z_text)
303                     })
304                     .collect(),
305             };
306             chart.draw_axis_ticks(
307                 axis,
308                 &labels[..],
309                 self.tick_size,
310                 self.axis_style,
311                 self.label_style.clone(),
312             )?;
313         }
314 
315         Ok(())
316     }
317 }
318