1use std::borrow::{Borrow, BorrowMut};
3use std::ops::{Deref, DerefMut};
4use std::sync::Arc;
5
6use super::mesh::SecondaryMeshStyle;
7use super::{ChartContext, ChartState, SeriesAnno};
8
9use crate::coord::cartesian::Cartesian2d;
10use crate::coord::ranged1d::{Ranged, ValueFormatter};
11use crate::coord::{CoordTranslate, ReverseCoordTranslate, Shift};
12
13use crate::drawing::DrawingArea;
14use crate::drawing::DrawingAreaErrorKind;
15use crate::element::{Drawable, PointCollection};
16
17use plotters_backend::{BackendCoord, DrawingBackend};
18
19pub struct DualCoordChartContext<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate> {
28 pub(super) primary: ChartContext<'a, DB, CT1>,
29 pub(super) secondary: ChartContext<'a, DB, CT2>,
30}
31
32pub struct DualCoordChartState<CT1: CoordTranslate, CT2: CoordTranslate> {
36 primary: ChartState<CT1>,
37 secondary: ChartState<CT2>,
38}
39
40impl<DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate>
41 DualCoordChartContext<'_, DB, CT1, CT2>
42{
43 pub fn into_chart_state(self) -> DualCoordChartState<CT1, CT2> {
45 DualCoordChartState {
46 primary: self.primary.into(),
47 secondary: self.secondary.into(),
48 }
49 }
50
51 pub fn into_shared_chart_state(self) -> DualCoordChartState<Arc<CT1>, Arc<CT2>> {
53 DualCoordChartState {
54 primary: self.primary.into_shared_chart_state(),
55 secondary: self.secondary.into_shared_chart_state(),
56 }
57 }
58
59 pub fn to_chart_state(&self) -> DualCoordChartState<CT1, CT2>
61 where
62 CT1: Clone,
63 CT2: Clone,
64 {
65 DualCoordChartState {
66 primary: self.primary.to_chart_state(),
67 secondary: self.secondary.to_chart_state(),
68 }
69 }
70}
71
72impl<CT1: CoordTranslate, CT2: CoordTranslate> DualCoordChartState<CT1, CT2> {
73 pub fn restore<DB: DrawingBackend>(
75 self,
76 area: &DrawingArea<DB, Shift>,
77 ) -> DualCoordChartContext<'_, DB, CT1, CT2> {
78 let primary = self.primary.restore(area);
79 let secondary = self
80 .secondary
81 .restore(&primary.plotting_area().strip_coord_spec());
82 DualCoordChartContext { primary, secondary }
83 }
84}
85
86impl<DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate>
87 From<DualCoordChartContext<'_, DB, CT1, CT2>> for DualCoordChartState<CT1, CT2>
88{
89 fn from(chart: DualCoordChartContext<'_, DB, CT1, CT2>) -> DualCoordChartState<CT1, CT2> {
90 chart.into_chart_state()
91 }
92}
93
94impl<'b, DB: DrawingBackend, CT1: CoordTranslate + Clone, CT2: CoordTranslate + Clone>
95 From<&'b DualCoordChartContext<'_, DB, CT1, CT2>> for DualCoordChartState<CT1, CT2>
96{
97 fn from(chart: &'b DualCoordChartContext<'_, DB, CT1, CT2>) -> DualCoordChartState<CT1, CT2> {
98 chart.to_chart_state()
99 }
100}
101
102impl<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate>
103 DualCoordChartContext<'a, DB, CT1, CT2>
104{
105 pub(super) fn new(mut primary: ChartContext<'a, DB, CT1>, secondary_coord: CT2) -> Self {
106 let secondary_drawing_area = primary
107 .drawing_area
108 .strip_coord_spec()
109 .apply_coord_spec(secondary_coord);
110 let mut secondary_x_label_area = [None, None];
111 let mut secondary_y_label_area = [None, None];
112
113 std::mem::swap(&mut primary.x_label_area[0], &mut secondary_x_label_area[0]);
114 std::mem::swap(&mut primary.y_label_area[1], &mut secondary_y_label_area[1]);
115
116 Self {
117 primary,
118 secondary: ChartContext {
119 x_label_area: secondary_x_label_area,
120 y_label_area: secondary_y_label_area,
121 drawing_area: secondary_drawing_area,
122 series_anno: vec![],
123 drawing_area_pos: (0, 0),
124 },
125 }
126 }
127
128 pub fn secondary_plotting_area(&self) -> &DrawingArea<DB, CT2> {
130 &self.secondary.drawing_area
131 }
132
133 pub fn borrow_secondary(&self) -> &ChartContext<'a, DB, CT2> {
136 &self.secondary
137 }
138}
139
140impl<DB: DrawingBackend, CT1: CoordTranslate, CT2: ReverseCoordTranslate>
141 DualCoordChartContext<'_, DB, CT1, CT2>
142{
143 pub fn into_secondary_coord_trans(self) -> impl Fn(BackendCoord) -> Option<CT2::From> {
145 let coord_spec = self.secondary.drawing_area.into_coord_spec();
146 move |coord| coord_spec.reverse_translate(coord)
147 }
148}
149
150impl<DB: DrawingBackend, CT1: ReverseCoordTranslate, CT2: ReverseCoordTranslate>
151 DualCoordChartContext<'_, DB, CT1, CT2>
152{
153 pub fn into_coord_trans_pair(
156 self,
157 ) -> (
158 impl Fn(BackendCoord) -> Option<CT1::From>,
159 impl Fn(BackendCoord) -> Option<CT2::From>,
160 ) {
161 let coord_spec_1 = self.primary.drawing_area.into_coord_spec();
162 let coord_spec_2 = self.secondary.drawing_area.into_coord_spec();
163 (
164 move |coord| coord_spec_1.reverse_translate(coord),
165 move |coord| coord_spec_2.reverse_translate(coord),
166 )
167 }
168}
169
170impl<
171 'a,
172 DB: DrawingBackend,
173 CT1: CoordTranslate,
174 XT,
175 YT,
176 SX: Ranged<ValueType = XT>,
177 SY: Ranged<ValueType = YT>,
178 > DualCoordChartContext<'a, DB, CT1, Cartesian2d<SX, SY>>
179where
180 SX: ValueFormatter<XT>,
181 SY: ValueFormatter<YT>,
182{
183 pub fn configure_secondary_axes<'b>(&'b mut self) -> SecondaryMeshStyle<'a, 'b, SX, SY, DB> {
185 SecondaryMeshStyle::new(&mut self.secondary)
186 }
187}
188
189impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged, SX: Ranged, SY: Ranged>
190 DualCoordChartContext<'a, DB, Cartesian2d<X, Y>, Cartesian2d<SX, SY>>
191{
192 pub fn draw_secondary_series<E, R, S>(
196 &mut self,
197 series: S,
198 ) -> Result<&mut SeriesAnno<'a, DB>, DrawingAreaErrorKind<DB::ErrorType>>
199 where
200 for<'b> &'b E: PointCollection<'b, (SX::ValueType, SY::ValueType)>,
201 E: Drawable<DB>,
202 R: Borrow<E>,
203 S: IntoIterator<Item = R>,
204 {
205 self.secondary.draw_series_impl(series)?;
206 Ok(self.primary.alloc_series_anno())
207 }
208}
209
210impl<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate>
211 Borrow<ChartContext<'a, DB, CT1>> for DualCoordChartContext<'a, DB, CT1, CT2>
212{
213 fn borrow(&self) -> &ChartContext<'a, DB, CT1> {
214 &self.primary
215 }
216}
217
218impl<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate>
219 BorrowMut<ChartContext<'a, DB, CT1>> for DualCoordChartContext<'a, DB, CT1, CT2>
220{
221 fn borrow_mut(&mut self) -> &mut ChartContext<'a, DB, CT1> {
222 &mut self.primary
223 }
224}
225
226impl<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate> Deref
227 for DualCoordChartContext<'a, DB, CT1, CT2>
228{
229 type Target = ChartContext<'a, DB, CT1>;
230 fn deref(&self) -> &Self::Target {
231 self.borrow()
232 }
233}
234
235impl<'a, DB: DrawingBackend, CT1: CoordTranslate, CT2: CoordTranslate> DerefMut
236 for DualCoordChartContext<'a, DB, CT1, CT2>
237{
238 fn deref_mut(&mut self) -> &mut Self::Target {
239 self.borrow_mut()
240 }
241}