| 1 | use std::marker::PhantomData; |
| 2 | |
| 3 | use super::builder::LabelAreaPosition; |
| 4 | use super::context::ChartContext; |
| 5 | use crate::coord::cartesian::{Cartesian2d, MeshLine}; |
| 6 | use crate::coord::ranged1d::{BoldPoints, LightPoints, Ranged, ValueFormatter}; |
| 7 | use crate::drawing::DrawingAreaErrorKind; |
| 8 | use crate::style::{ |
| 9 | AsRelative, Color, FontDesc, FontFamily, FontStyle, IntoTextStyle, RGBColor, ShapeStyle, |
| 10 | SizeDesc, TextStyle, |
| 11 | }; |
| 12 | |
| 13 | use plotters_backend::DrawingBackend; |
| 14 | |
| 15 | /// The style used to describe the mesh and axis for a secondary coordinate system. |
| 16 | pub struct SecondaryMeshStyle<'a, 'b, X: Ranged, Y: Ranged, DB: DrawingBackend> { |
| 17 | style: MeshStyle<'a, 'b, X, Y, DB>, |
| 18 | } |
| 19 | |
| 20 | impl<'a, 'b, XT, YT, X: Ranged<ValueType = XT>, Y: Ranged<ValueType = YT>, DB: DrawingBackend> |
| 21 | SecondaryMeshStyle<'a, 'b, X, Y, DB> |
| 22 | where |
| 23 | X: ValueFormatter<XT>, |
| 24 | Y: ValueFormatter<YT>, |
| 25 | { |
| 26 | pub(super) fn new(target: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self { |
| 27 | let mut style = target.configure_mesh(); |
| 28 | style.draw_x_mesh = false; |
| 29 | style.draw_y_mesh = false; |
| 30 | Self { style } |
| 31 | } |
| 32 | |
| 33 | /// Set the style definition for the axis |
| 34 | /// - `style`: The style for the axis |
| 35 | pub fn axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self { |
| 36 | self.style.axis_style(style); |
| 37 | self |
| 38 | } |
| 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 used to adjust label position for histograms, but since plotters 0.3, this |
| 42 | /// use case is deprecated, see [SegmentedCoord coord decorator](../coord/ranged1d/trait.IntoSegmentedCoord.html) for more details |
| 43 | /// - `value`: The offset in pixel |
| 44 | pub fn x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 45 | self.style.x_label_offset(value); |
| 46 | self |
| 47 | } |
| 48 | |
| 49 | /// The offset of y labels. This is used when we want to place the label in the middle of |
| 50 | /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this |
| 51 | /// use case is deprecated, see [SegmentedCoord coord decorator](../coord/ranged1d/trait.IntoSegmentedCoord.html) for more details |
| 52 | /// - `value`: The offset in pixel |
| 53 | pub fn y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 54 | self.style.y_label_offset(value); |
| 55 | self |
| 56 | } |
| 57 | |
| 58 | /// Set how many labels for the X axis at most |
| 59 | /// - `value`: The maximum desired number of labels in the X axis |
| 60 | pub fn x_labels(&mut self, value: usize) -> &mut Self { |
| 61 | self.style.x_labels(value); |
| 62 | self |
| 63 | } |
| 64 | |
| 65 | /// Set how many label for the Y axis at most |
| 66 | /// - `value`: The maximum desired number of labels in the Y axis |
| 67 | pub fn y_labels(&mut self, value: usize) -> &mut Self { |
| 68 | self.style.y_labels(value); |
| 69 | self |
| 70 | } |
| 71 | |
| 72 | /// Set the formatter function for the X label text |
| 73 | /// - `fmt`: The formatter function |
| 74 | pub fn x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self { |
| 75 | self.style.x_label_formatter(fmt); |
| 76 | self |
| 77 | } |
| 78 | |
| 79 | /// Set the formatter function for the Y label text |
| 80 | /// - `fmt`: The formatter function |
| 81 | pub fn y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self { |
| 82 | self.style.y_label_formatter(fmt); |
| 83 | self |
| 84 | } |
| 85 | |
| 86 | /// Set the axis description's style. If not given, use label style instead. |
| 87 | /// - `style`: The text style that would be applied to descriptions |
| 88 | pub fn axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 89 | self.style |
| 90 | .axis_desc_style(style.into_text_style(&self.style.parent_size)); |
| 91 | self |
| 92 | } |
| 93 | |
| 94 | /// Set the X axis's description |
| 95 | /// - `desc`: The description of the X axis |
| 96 | pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self { |
| 97 | self.style.x_desc(desc); |
| 98 | self |
| 99 | } |
| 100 | |
| 101 | /// Set the Y axis's description |
| 102 | /// - `desc`: The description of the Y axis |
| 103 | pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self { |
| 104 | self.style.y_desc(desc); |
| 105 | self |
| 106 | } |
| 107 | |
| 108 | /// Draw the axes for the secondary coordinate system |
| 109 | pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> { |
| 110 | self.style.draw() |
| 111 | } |
| 112 | |
| 113 | /// Set the label style for the secondary axis |
| 114 | pub fn label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 115 | self.style.label_style(style); |
| 116 | self |
| 117 | } |
| 118 | |
| 119 | /// Set all the tick marks to the same size |
| 120 | /// `value`: The new size |
| 121 | pub fn set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 122 | let size = value.in_pixels(&self.style.parent_size); |
| 123 | self.style.x_tick_size = [size, size]; |
| 124 | self.style.y_tick_size = [size, size]; |
| 125 | self |
| 126 | } |
| 127 | /// Sets the tick mark size for a given label area position. |
| 128 | /// `value`: The new size |
| 129 | pub fn set_tick_mark_size<S: SizeDesc>( |
| 130 | &mut self, |
| 131 | pos: LabelAreaPosition, |
| 132 | value: S, |
| 133 | ) -> &mut Self { |
| 134 | *match pos { |
| 135 | LabelAreaPosition::Top => &mut self.style.x_tick_size[0], |
| 136 | LabelAreaPosition::Bottom => &mut self.style.x_tick_size[1], |
| 137 | LabelAreaPosition::Left => &mut self.style.y_tick_size[0], |
| 138 | LabelAreaPosition::Right => &mut self.style.y_tick_size[1], |
| 139 | } = value.in_pixels(&self.style.parent_size); |
| 140 | self |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | /// The struct that is used for tracking the configuration of a mesh of any chart |
| 145 | pub struct MeshStyle<'a, 'b, X: Ranged, Y: Ranged, DB: DrawingBackend> { |
| 146 | pub(super) parent_size: (u32, u32), |
| 147 | pub(super) draw_x_mesh: bool, |
| 148 | pub(super) draw_y_mesh: bool, |
| 149 | pub(super) draw_x_axis: bool, |
| 150 | pub(super) draw_y_axis: bool, |
| 151 | pub(super) x_label_offset: i32, |
| 152 | pub(super) y_label_offset: i32, |
| 153 | pub(super) x_light_lines_limit: usize, |
| 154 | pub(super) y_light_lines_limit: usize, |
| 155 | pub(super) n_x_labels: usize, |
| 156 | pub(super) n_y_labels: usize, |
| 157 | pub(super) axis_desc_style: Option<TextStyle<'b>>, |
| 158 | pub(super) x_desc: Option<String>, |
| 159 | pub(super) y_desc: Option<String>, |
| 160 | pub(super) bold_line_style: Option<ShapeStyle>, |
| 161 | pub(super) light_line_style: Option<ShapeStyle>, |
| 162 | pub(super) axis_style: Option<ShapeStyle>, |
| 163 | pub(super) x_label_style: Option<TextStyle<'b>>, |
| 164 | pub(super) y_label_style: Option<TextStyle<'b>>, |
| 165 | pub(super) format_x: Option<&'b dyn Fn(&X::ValueType) -> String>, |
| 166 | pub(super) format_y: Option<&'b dyn Fn(&Y::ValueType) -> String>, |
| 167 | pub(super) target: Option<&'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>>, |
| 168 | pub(super) _phantom_data: PhantomData<(X, Y)>, |
| 169 | pub(super) x_tick_size: [i32; 2], |
| 170 | pub(super) y_tick_size: [i32; 2], |
| 171 | } |
| 172 | |
| 173 | impl<'a, 'b, X, Y, XT, YT, DB> MeshStyle<'a, 'b, X, Y, DB> |
| 174 | where |
| 175 | X: Ranged<ValueType = XT> + ValueFormatter<XT>, |
| 176 | Y: Ranged<ValueType = YT> + ValueFormatter<YT>, |
| 177 | DB: DrawingBackend, |
| 178 | { |
| 179 | pub(crate) fn new(chart: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self { |
| 180 | let base_tick_size = (5u32).percent().max(5).in_pixels(chart.plotting_area()); |
| 181 | |
| 182 | let mut x_tick_size = [base_tick_size, base_tick_size]; |
| 183 | let mut y_tick_size = [base_tick_size, base_tick_size]; |
| 184 | |
| 185 | for idx in 0..2 { |
| 186 | if chart.is_overlapping_drawing_area(chart.x_label_area[idx].as_ref()) { |
| 187 | x_tick_size[idx] = -x_tick_size[idx]; |
| 188 | } |
| 189 | if chart.is_overlapping_drawing_area(chart.y_label_area[idx].as_ref()) { |
| 190 | y_tick_size[idx] = -y_tick_size[idx]; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | MeshStyle { |
| 195 | parent_size: chart.drawing_area.dim_in_pixel(), |
| 196 | axis_style: None, |
| 197 | x_label_offset: 0, |
| 198 | y_label_offset: 0, |
| 199 | draw_x_mesh: true, |
| 200 | draw_y_mesh: true, |
| 201 | draw_x_axis: true, |
| 202 | draw_y_axis: true, |
| 203 | x_light_lines_limit: 10, |
| 204 | y_light_lines_limit: 10, |
| 205 | n_x_labels: 11, |
| 206 | n_y_labels: 11, |
| 207 | bold_line_style: None, |
| 208 | light_line_style: None, |
| 209 | x_label_style: None, |
| 210 | y_label_style: None, |
| 211 | format_x: None, |
| 212 | format_y: None, |
| 213 | target: Some(chart), |
| 214 | _phantom_data: PhantomData, |
| 215 | x_desc: None, |
| 216 | y_desc: None, |
| 217 | axis_desc_style: None, |
| 218 | x_tick_size, |
| 219 | y_tick_size, |
| 220 | } |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | impl<'a, 'b, X, Y, DB> MeshStyle<'a, 'b, X, Y, DB> |
| 225 | where |
| 226 | X: Ranged, |
| 227 | Y: Ranged, |
| 228 | DB: DrawingBackend, |
| 229 | { |
| 230 | /// Set all the tick mark to the same size |
| 231 | /// `value`: The new size |
| 232 | pub fn set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 233 | let size = value.in_pixels(&self.parent_size); |
| 234 | self.x_tick_size = [size, size]; |
| 235 | self.y_tick_size = [size, size]; |
| 236 | self |
| 237 | } |
| 238 | |
| 239 | /// Set the tick mark size on the axes. When this is set to negative, the axis value label will |
| 240 | /// become inward. |
| 241 | /// |
| 242 | /// - `pos`: The which label area we want to set |
| 243 | /// - `value`: The size specification |
| 244 | pub fn set_tick_mark_size<S: SizeDesc>( |
| 245 | &mut self, |
| 246 | pos: LabelAreaPosition, |
| 247 | value: S, |
| 248 | ) -> &mut Self { |
| 249 | *match pos { |
| 250 | LabelAreaPosition::Top => &mut self.x_tick_size[0], |
| 251 | LabelAreaPosition::Bottom => &mut self.x_tick_size[1], |
| 252 | LabelAreaPosition::Left => &mut self.y_tick_size[0], |
| 253 | LabelAreaPosition::Right => &mut self.y_tick_size[1], |
| 254 | } = value.in_pixels(&self.parent_size); |
| 255 | self |
| 256 | } |
| 257 | |
| 258 | /// The offset of x labels. This is used when we want to place the label in the middle of |
| 259 | /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this |
| 260 | /// use case is deprecated, see [SegmentedCoord coord decorator](../coord/ranged1d/trait.IntoSegmentedCoord.html) for more details |
| 261 | /// - `value`: The offset in pixel |
| 262 | pub fn x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 263 | self.x_label_offset = value.in_pixels(&self.parent_size); |
| 264 | self |
| 265 | } |
| 266 | |
| 267 | /// The offset of y labels. This is used when we want to place the label in the middle of |
| 268 | /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this |
| 269 | /// use case is deprecated, see [SegmentedCoord coord decorator](../coord/ranged1d/trait.IntoSegmentedCoord.html) for more details |
| 270 | /// - `value`: The offset in pixel |
| 271 | pub fn y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self { |
| 272 | self.y_label_offset = value.in_pixels(&self.parent_size); |
| 273 | self |
| 274 | } |
| 275 | |
| 276 | /// Disable the mesh for the x axis. |
| 277 | pub fn disable_x_mesh(&mut self) -> &mut Self { |
| 278 | self.draw_x_mesh = false; |
| 279 | self |
| 280 | } |
| 281 | |
| 282 | /// Disable the mesh for the y axis |
| 283 | pub fn disable_y_mesh(&mut self) -> &mut Self { |
| 284 | self.draw_y_mesh = false; |
| 285 | self |
| 286 | } |
| 287 | |
| 288 | /// Disable drawing the X axis |
| 289 | pub fn disable_x_axis(&mut self) -> &mut Self { |
| 290 | self.draw_x_axis = false; |
| 291 | self |
| 292 | } |
| 293 | |
| 294 | /// Disable drawing the Y axis |
| 295 | pub fn disable_y_axis(&mut self) -> &mut Self { |
| 296 | self.draw_y_axis = false; |
| 297 | self |
| 298 | } |
| 299 | |
| 300 | /// Disable drawing all meshes |
| 301 | pub fn disable_mesh(&mut self) -> &mut Self { |
| 302 | self.disable_x_mesh().disable_y_mesh() |
| 303 | } |
| 304 | |
| 305 | /// Disable drawing all axes |
| 306 | pub fn disable_axes(&mut self) -> &mut Self { |
| 307 | self.disable_x_axis().disable_y_axis() |
| 308 | } |
| 309 | |
| 310 | /// Set the style definition for the axis |
| 311 | /// - `style`: The style for the axis |
| 312 | pub fn axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self { |
| 313 | self.axis_style = Some(style.into()); |
| 314 | self |
| 315 | } |
| 316 | |
| 317 | /// Set the maximum number of divisions for the minor grid |
| 318 | /// - `value`: Maximum desired divisions between two consecutive X labels |
| 319 | pub fn x_max_light_lines(&mut self, value: usize) -> &mut Self { |
| 320 | self.x_light_lines_limit = value; |
| 321 | self |
| 322 | } |
| 323 | |
| 324 | /// Set the maximum number of divisions for the minor grid |
| 325 | /// - `value`: Maximum desired divisions between two consecutive Y labels |
| 326 | pub fn y_max_light_lines(&mut self, value: usize) -> &mut Self { |
| 327 | self.y_light_lines_limit = value; |
| 328 | self |
| 329 | } |
| 330 | |
| 331 | /// Set the maximum number of divisions for the minor grid |
| 332 | /// - `value`: Maximum desired divisions between two consecutive labels in X and Y |
| 333 | pub fn max_light_lines(&mut self, value: usize) -> &mut Self { |
| 334 | self.x_light_lines_limit = value; |
| 335 | self.y_light_lines_limit = value; |
| 336 | self |
| 337 | } |
| 338 | |
| 339 | /// Set how many labels for the X axis at most |
| 340 | /// - `value`: The maximum desired number of labels in the X axis |
| 341 | pub fn x_labels(&mut self, value: usize) -> &mut Self { |
| 342 | self.n_x_labels = value; |
| 343 | self |
| 344 | } |
| 345 | |
| 346 | /// Set how many label for the Y axis at most |
| 347 | /// - `value`: The maximum desired number of labels in the Y axis |
| 348 | pub fn y_labels(&mut self, value: usize) -> &mut Self { |
| 349 | self.n_y_labels = value; |
| 350 | self |
| 351 | } |
| 352 | |
| 353 | /// Set the style for the coarse grind grid |
| 354 | /// - `style`: This is the coarse grind grid style |
| 355 | pub fn bold_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self { |
| 356 | self.bold_line_style = Some(style.into()); |
| 357 | self |
| 358 | } |
| 359 | |
| 360 | /// Set the style for the fine grind grid |
| 361 | /// - `style`: The fine grind grid style |
| 362 | pub fn light_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self { |
| 363 | self.light_line_style = Some(style.into()); |
| 364 | self |
| 365 | } |
| 366 | |
| 367 | /// Set the style of the label text |
| 368 | /// - `style`: The text style that would be applied to the labels |
| 369 | pub fn label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 370 | let style = style.into_text_style(&self.parent_size); |
| 371 | self.x_label_style = Some(style.clone()); |
| 372 | self.y_label_style = Some(style); |
| 373 | self |
| 374 | } |
| 375 | |
| 376 | /// Set the style of the label X axis text |
| 377 | /// - `style`: The text style that would be applied to the labels |
| 378 | pub fn x_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 379 | self.x_label_style = Some(style.into_text_style(&self.parent_size)); |
| 380 | self |
| 381 | } |
| 382 | |
| 383 | /// Set the style of the label Y axis text |
| 384 | /// - `style`: The text style that would be applied to the labels |
| 385 | pub fn y_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 386 | self.y_label_style = Some(style.into_text_style(&self.parent_size)); |
| 387 | self |
| 388 | } |
| 389 | |
| 390 | /// Set the formatter function for the X label text |
| 391 | /// - `fmt`: The formatter function |
| 392 | pub fn x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self { |
| 393 | self.format_x = Some(fmt); |
| 394 | self |
| 395 | } |
| 396 | |
| 397 | /// Set the formatter function for the Y label text |
| 398 | /// - `fmt`: The formatter function |
| 399 | pub fn y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self { |
| 400 | self.format_y = Some(fmt); |
| 401 | self |
| 402 | } |
| 403 | |
| 404 | /// Set the axis description's style. If not given, use label style instead. |
| 405 | /// - `style`: The text style that would be applied to descriptions |
| 406 | pub fn axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self { |
| 407 | self.axis_desc_style = Some(style.into_text_style(&self.parent_size)); |
| 408 | self |
| 409 | } |
| 410 | |
| 411 | /// Set the X axis's description |
| 412 | /// - `desc`: The description of the X axis |
| 413 | pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self { |
| 414 | self.x_desc = Some(desc.into()); |
| 415 | self |
| 416 | } |
| 417 | |
| 418 | /// Set the Y axis's description |
| 419 | /// - `desc`: The description of the Y axis |
| 420 | pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self { |
| 421 | self.y_desc = Some(desc.into()); |
| 422 | self |
| 423 | } |
| 424 | |
| 425 | /// Draw the configured mesh on the target plot |
| 426 | pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> |
| 427 | where |
| 428 | X: ValueFormatter<<X as Ranged>::ValueType>, |
| 429 | Y: ValueFormatter<<Y as Ranged>::ValueType>, |
| 430 | { |
| 431 | let target = self.target.take().unwrap(); |
| 432 | |
| 433 | let default_mesh_color_1 = RGBColor(0, 0, 0).mix(0.2); |
| 434 | let default_mesh_color_2 = RGBColor(0, 0, 0).mix(0.1); |
| 435 | let default_axis_color = RGBColor(0, 0, 0); |
| 436 | let default_label_font = FontDesc::new( |
| 437 | FontFamily::SansSerif, |
| 438 | f64::from((12i32).percent().max(12).in_pixels(&self.parent_size)), |
| 439 | FontStyle::Normal, |
| 440 | ); |
| 441 | |
| 442 | let bold_style = self |
| 443 | .bold_line_style |
| 444 | .unwrap_or_else(|| (&default_mesh_color_1).into()); |
| 445 | let light_style = self |
| 446 | .light_line_style |
| 447 | .unwrap_or_else(|| (&default_mesh_color_2).into()); |
| 448 | let axis_style = self |
| 449 | .axis_style |
| 450 | .unwrap_or_else(|| (&default_axis_color).into()); |
| 451 | |
| 452 | let x_label_style = self |
| 453 | .x_label_style |
| 454 | .clone() |
| 455 | .unwrap_or_else(|| default_label_font.clone().into()); |
| 456 | |
| 457 | let y_label_style = self |
| 458 | .y_label_style |
| 459 | .clone() |
| 460 | .unwrap_or_else(|| default_label_font.into()); |
| 461 | |
| 462 | let axis_desc_style = self |
| 463 | .axis_desc_style |
| 464 | .clone() |
| 465 | .unwrap_or_else(|| x_label_style.clone()); |
| 466 | |
| 467 | target.draw_mesh( |
| 468 | ( |
| 469 | LightPoints::new(self.n_y_labels, self.n_y_labels * self.y_light_lines_limit), |
| 470 | LightPoints::new(self.n_x_labels, self.n_x_labels * self.x_light_lines_limit), |
| 471 | ), |
| 472 | &light_style, |
| 473 | &x_label_style, |
| 474 | &y_label_style, |
| 475 | |_, _, _| None, |
| 476 | self.draw_x_mesh, |
| 477 | self.draw_y_mesh, |
| 478 | self.x_label_offset, |
| 479 | self.y_label_offset, |
| 480 | false, |
| 481 | false, |
| 482 | &axis_style, |
| 483 | &axis_desc_style, |
| 484 | self.x_desc.clone(), |
| 485 | self.y_desc.clone(), |
| 486 | self.x_tick_size, |
| 487 | self.y_tick_size, |
| 488 | )?; |
| 489 | |
| 490 | target.draw_mesh( |
| 491 | (BoldPoints(self.n_y_labels), BoldPoints(self.n_x_labels)), |
| 492 | &bold_style, |
| 493 | &x_label_style, |
| 494 | &y_label_style, |
| 495 | |xr, yr, m| match m { |
| 496 | MeshLine::XMesh(_, _, v) => { |
| 497 | if self.draw_x_axis { |
| 498 | if let Some(fmt_func) = self.format_x { |
| 499 | Some(fmt_func(v)) |
| 500 | } else { |
| 501 | Some(xr.format_ext(v)) |
| 502 | } |
| 503 | } else { |
| 504 | None |
| 505 | } |
| 506 | } |
| 507 | MeshLine::YMesh(_, _, v) => { |
| 508 | if self.draw_y_axis { |
| 509 | if let Some(fmt_func) = self.format_y { |
| 510 | Some(fmt_func(v)) |
| 511 | } else { |
| 512 | Some(yr.format_ext(v)) |
| 513 | } |
| 514 | } else { |
| 515 | None |
| 516 | } |
| 517 | } |
| 518 | }, |
| 519 | self.draw_x_mesh, |
| 520 | self.draw_y_mesh, |
| 521 | self.x_label_offset, |
| 522 | self.y_label_offset, |
| 523 | self.draw_x_axis, |
| 524 | self.draw_y_axis, |
| 525 | &axis_style, |
| 526 | &axis_desc_style, |
| 527 | None, |
| 528 | None, |
| 529 | self.x_tick_size, |
| 530 | self.y_tick_size, |
| 531 | ) |
| 532 | } |
| 533 | } |
| 534 | |