1 | use std::ops::Range; |
2 | |
3 | use plotters_backend::{BackendCoord, DrawingBackend}; |
4 | |
5 | use crate::chart::{ChartContext, DualCoordChartContext, MeshStyle}; |
6 | use crate::coord::{ |
7 | cartesian::Cartesian2d, |
8 | ranged1d::{AsRangedCoord, Ranged, ValueFormatter}, |
9 | Shift, |
10 | }; |
11 | use crate::drawing::DrawingArea; |
12 | |
13 | mod draw_impl; |
14 | |
15 | impl<'a, DB, XT, YT, X, Y> ChartContext<'a, DB, Cartesian2d<X, Y>> |
16 | where |
17 | DB: DrawingBackend, |
18 | X: Ranged<ValueType = XT> + ValueFormatter<XT>, |
19 | Y: Ranged<ValueType = YT> + ValueFormatter<YT>, |
20 | { |
21 | pub(crate) fn is_overlapping_drawing_area( |
22 | &self, |
23 | area: Option<&DrawingArea<DB, Shift>>, |
24 | ) -> bool { |
25 | if let Some(area) = area { |
26 | let (x0, y0) = area.get_base_pixel(); |
27 | let (w, h) = area.dim_in_pixel(); |
28 | let (x1, y1) = (x0 + w as i32, y0 + h as i32); |
29 | let (dx0, dy0) = self.drawing_area.get_base_pixel(); |
30 | let (w, h) = self.drawing_area.dim_in_pixel(); |
31 | let (dx1, dy1) = (dx0 + w as i32, dy0 + h as i32); |
32 | |
33 | let (ox0, ox1) = (x0.max(dx0), x1.min(dx1)); |
34 | let (oy0, oy1) = (y0.max(dy0), y1.min(dy1)); |
35 | |
36 | ox1 > ox0 && oy1 > oy0 |
37 | } else { |
38 | false |
39 | } |
40 | } |
41 | |
42 | /// Initialize a mesh configuration object and mesh drawing can be finalized by calling |
43 | /// the function `MeshStyle::draw`. |
44 | pub fn configure_mesh(&mut self) -> MeshStyle<'a, '_, X, Y, DB> { |
45 | MeshStyle::new(self) |
46 | } |
47 | } |
48 | |
49 | impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesian2d<X, Y>> { |
50 | /// Get the range of X axis |
51 | pub fn x_range(&self) -> Range<X::ValueType> { |
52 | self.drawing_area.get_x_range() |
53 | } |
54 | |
55 | /// Get range of the Y axis |
56 | pub fn y_range(&self) -> Range<Y::ValueType> { |
57 | self.drawing_area.get_y_range() |
58 | } |
59 | |
60 | /// Maps the coordinate to the backend coordinate. This is typically used |
61 | /// with an interactive chart. |
62 | pub fn backend_coord(&self, coord: &(X::ValueType, Y::ValueType)) -> BackendCoord { |
63 | self.drawing_area.map_coordinate(coord) |
64 | } |
65 | } |
66 | |
67 | impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesian2d<X, Y>> { |
68 | /// Convert this chart context into a dual axis chart context and attach a second coordinate spec |
69 | /// on the chart context. For more detailed information, see documentation for [struct DualCoordChartContext](struct.DualCoordChartContext.html) |
70 | /// |
71 | /// - `x_coord`: The coordinate spec for the X axis |
72 | /// - `y_coord`: The coordinate spec for the Y axis |
73 | /// - **returns** The newly created dual spec chart context |
74 | #[allow (clippy::type_complexity)] |
75 | pub fn set_secondary_coord<SX: AsRangedCoord, SY: AsRangedCoord>( |
76 | self, |
77 | x_coord: SX, |
78 | y_coord: SY, |
79 | ) -> DualCoordChartContext< |
80 | 'a, |
81 | DB, |
82 | Cartesian2d<X, Y>, |
83 | Cartesian2d<SX::CoordDescType, SY::CoordDescType>, |
84 | > { |
85 | let mut pixel_range = self.drawing_area.get_pixel_range(); |
86 | pixel_range.1 = pixel_range.1.end..pixel_range.1.start; |
87 | |
88 | DualCoordChartContext::new(self, Cartesian2d::new(x_coord, y_coord, pixel_range)) |
89 | } |
90 | } |
91 | |