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