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 /// The configurations about the 3D plot's axes
17 pub struct Axes3dStyle<'a, 'b, X: Ranged, Y: Ranged, Z: Ranged, DB: DrawingBackend> {
18     pub(super) parent_size: (u32, u32),
19     pub(super) target: Option<&'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>>,
20     pub(super) tick_size: i32,
21     pub(super) n_labels: [usize; 3],
22     pub(super) bold_line_style: ShapeStyle,
23     pub(super) light_line_style: ShapeStyle,
24     pub(super) axis_panel_style: ShapeStyle,
25     pub(super) axis_style: ShapeStyle,
26     pub(super) label_style: TextStyle<'b>,
27     pub(super) format_x: &'b dyn Fn(&X::ValueType) -> String,
28     pub(super) format_y: &'b dyn Fn(&Y::ValueType) -> String,
29     pub(super) format_z: &'b dyn Fn(&Z::ValueType) -> String,
30     _phantom: PhantomData<&'a (X, Y, Z)>,
31 }
32 
33 impl<'a, 'b, X, Y, Z, XT, YT, ZT, DB> Axes3dStyle<'a, 'b, X, Y, Z, DB>
34 where
35     X: Ranged<ValueType = XT> + ValueFormatter<XT>,
36     Y: Ranged<ValueType = YT> + ValueFormatter<YT>,
37     Z: Ranged<ValueType = ZT> + ValueFormatter<ZT>,
38     DB: DrawingBackend,
39 {
40     /// Set the size of the tick mark
tick_size<Size: SizeDesc>(&mut self, size: Size) -> &mut Self41     pub fn tick_size<Size: SizeDesc>(&mut self, size: Size) -> &mut Self {
42         let actual_size = size.in_pixels(&self.parent_size);
43         self.tick_size = actual_size;
44         self
45     }
46 
47     /// Set the number of labels on the X axes
x_labels(&mut self, n: usize) -> &mut Self48     pub fn x_labels(&mut self, n: usize) -> &mut Self {
49         self.n_labels[0] = n;
50         self
51     }
52 
53     /// Set the number of labels on the Y axes
y_labels(&mut self, n: usize) -> &mut Self54     pub fn y_labels(&mut self, n: usize) -> &mut Self {
55         self.n_labels[1] = n;
56         self
57     }
58 
59     /// Set the number of labels on the Z axes
z_labels(&mut self, n: usize) -> &mut Self60     pub fn z_labels(&mut self, n: usize) -> &mut Self {
61         self.n_labels[2] = n;
62         self
63     }
64 
axis_panel_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self65     pub fn axis_panel_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
66         self.axis_panel_style = style.into();
67         self
68     }
69 
bold_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self70     pub fn bold_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
71         self.bold_line_style = style.into();
72         self
73     }
74 
light_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self75     pub fn light_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self {
76         self.light_line_style = style.into();
77         self
78     }
79 
label_style<S: Into<TextStyle<'b>>>(&mut self, style: S) -> &mut Self80     pub fn label_style<S: Into<TextStyle<'b>>>(&mut self, style: S) -> &mut Self {
81         self.label_style = style.into();
82         self
83     }
84 
x_formatter<F: Fn(&X::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self85     pub fn x_formatter<F: Fn(&X::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
86         self.format_x = f;
87         self
88     }
89 
y_formatter<F: Fn(&Y::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self90     pub fn y_formatter<F: Fn(&Y::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
91         self.format_y = f;
92         self
93     }
94 
z_formatter<F: Fn(&Z::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self95     pub fn z_formatter<F: Fn(&Z::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self {
96         self.format_z = f;
97         self
98     }
99 
new(chart: &'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>) -> Self100     pub(crate) fn new(chart: &'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>) -> Self {
101         let parent_size = chart.drawing_area.dim_in_pixel();
102         let base_tick_size = (5u32).percent().max(5).in_pixels(chart.plotting_area());
103         let tick_size = base_tick_size;
104         Self {
105             parent_size,
106             tick_size,
107             n_labels: [10, 10, 10],
108             bold_line_style: Into::<ShapeStyle>::into(&BLACK.mix(0.2)),
109             light_line_style: Into::<ShapeStyle>::into(&TRANSPARENT),
110             axis_panel_style: Into::<ShapeStyle>::into(&BLACK.mix(0.1)),
111             axis_style: Into::<ShapeStyle>::into(&BLACK.mix(0.8)),
112             label_style: ("sans-serf", (12).percent().max(12).in_pixels(&parent_size)).into(),
113             format_x: &X::format,
114             format_y: &Y::format,
115             format_z: &Z::format,
116             _phantom: PhantomData,
117             target: Some(chart),
118         }
119     }
draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> where XT: Clone, YT: Clone, ZT: Clone,120     pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>>
121     where
122         XT: Clone,
123         YT: Clone,
124         ZT: Clone,
125     {
126         let chart = self.target.take().unwrap();
127         let kps_bold = chart.get_key_points(
128             BoldPoints(self.n_labels[0]),
129             BoldPoints(self.n_labels[1]),
130             BoldPoints(self.n_labels[2]),
131         );
132         let kps_light = chart.get_key_points(
133             LightPoints::new(self.n_labels[0], self.n_labels[0] * 10),
134             LightPoints::new(self.n_labels[1], self.n_labels[1] * 10),
135             LightPoints::new(self.n_labels[2], self.n_labels[2] * 10),
136         );
137 
138         let panels = chart.draw_axis_panels(
139             &kps_bold,
140             &kps_light,
141             self.axis_panel_style.clone(),
142             self.bold_line_style.clone(),
143             self.light_line_style.clone(),
144         )?;
145 
146         for i in 0..3 {
147             let axis = chart.draw_axis(i, &panels, self.axis_style.clone())?;
148             let labels: Vec<_> = match i {
149                 0 => kps_bold
150                     .x_points
151                     .iter()
152                     .map(|x| {
153                         let x_text = (self.format_x)(x);
154                         let mut p = axis[0].clone();
155                         p[0] = Coord3D::X(x.clone());
156                         (p, x_text)
157                     })
158                     .collect(),
159                 1 => kps_bold
160                     .y_points
161                     .iter()
162                     .map(|y| {
163                         let y_text = (self.format_y)(y);
164                         let mut p = axis[0].clone();
165                         p[1] = Coord3D::Y(y.clone());
166                         (p, y_text)
167                     })
168                     .collect(),
169                 _ => kps_bold
170                     .z_points
171                     .iter()
172                     .map(|z| {
173                         let z_text = (self.format_z)(z);
174                         let mut p = axis[0].clone();
175                         p[2] = Coord3D::Z(z.clone());
176                         (p, z_text)
177                     })
178                     .collect(),
179             };
180             chart.draw_axis_ticks(
181                 axis,
182                 &labels[..],
183                 self.tick_size,
184                 self.axis_style.clone(),
185                 self.label_style.clone(),
186             )?;
187         }
188 
189         Ok(())
190     }
191 }
192