1use std::borrow::Borrow;
2
3use plotters_backend::{BackendCoord, DrawingBackend};
4
5use crate::chart::{SeriesAnno, SeriesLabelStyle};
6use crate::coord::{CoordTranslate, ReverseCoordTranslate, Shift};
7use crate::drawing::{DrawingArea, DrawingAreaErrorKind};
8use crate::element::{CoordMapper, Drawable, PointCollection};
9
10pub(super) mod cartesian2d;
11pub(super) mod cartesian3d;
12
13pub(super) use cartesian3d::Coord3D;
14
15pub struct ChartContext<'a, DB: DrawingBackend, CT: CoordTranslate> {
26 pub(crate) x_label_area: [Option<DrawingArea<DB, Shift>>; 2],
27 pub(crate) y_label_area: [Option<DrawingArea<DB, Shift>>; 2],
28 pub(crate) drawing_area: DrawingArea<DB, CT>,
29 pub(crate) series_anno: Vec<SeriesAnno<'a, DB>>,
30 pub(crate) drawing_area_pos: (i32, i32),
31}
32
33impl<'a, DB: DrawingBackend, CT: ReverseCoordTranslate> ChartContext<'a, DB, CT> {
34 pub fn into_coord_trans(self) -> impl Fn(BackendCoord) -> Option<CT::From> {
36 let coord_spec = self.drawing_area.into_coord_spec();
37 move |coord| coord_spec.reverse_translate(coord)
38 }
39}
40
41impl<'a, DB: DrawingBackend, CT: CoordTranslate> ChartContext<'a, DB, CT> {
42 pub fn configure_series_labels<'b>(&'b mut self) -> SeriesLabelStyle<'a, 'b, DB, CT>
71 where
72 DB: 'a,
73 {
74 SeriesLabelStyle::new(self)
75 }
76
77 pub fn plotting_area(&self) -> &DrawingArea<DB, CT> {
79 &self.drawing_area
80 }
81
82 pub fn as_coord_spec(&self) -> &CT {
84 self.drawing_area.as_coord_spec()
85 }
86
87 pub(crate) fn draw_series_impl<B, E, R, S>(
93 &mut self,
94 series: S,
95 ) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>>
96 where
97 B: CoordMapper,
98 for<'b> &'b E: PointCollection<'b, CT::From, B>,
99 E: Drawable<DB, B>,
100 R: Borrow<E>,
101 S: IntoIterator<Item = R>,
102 {
103 for element in series {
104 self.drawing_area.draw(element.borrow())?;
105 }
106 Ok(())
107 }
108
109 pub(crate) fn alloc_series_anno(&mut self) -> &mut SeriesAnno<'a, DB> {
110 let idx = self.series_anno.len();
111 self.series_anno.push(SeriesAnno::new());
112 &mut self.series_anno[idx]
113 }
114
115 pub fn draw_series<B, E, R, S>(
121 &mut self,
122 series: S,
123 ) -> Result<&mut SeriesAnno<'a, DB>, DrawingAreaErrorKind<DB::ErrorType>>
124 where
125 B: CoordMapper,
126 for<'b> &'b E: PointCollection<'b, CT::From, B>,
127 E: Drawable<DB, B>,
128 R: Borrow<E>,
129 S: IntoIterator<Item = R>,
130 {
131 self.draw_series_impl(series)?;
132 Ok(self.alloc_series_anno())
133 }
134}
135
136#[cfg(test)]
137mod test {
138 use crate::prelude::*;
139
140 #[test]
141 fn test_chart_context() {
142 let drawing_area = create_mocked_drawing_area(200, 200, |_| {});
143
144 drawing_area.fill(&WHITE).expect("Fill");
145
146 let mut chart = ChartBuilder::on(&drawing_area)
147 .caption("Test Title", ("serif", 10))
148 .x_label_area_size(20)
149 .y_label_area_size(20)
150 .set_label_area_size(LabelAreaPosition::Top, 20)
151 .set_label_area_size(LabelAreaPosition::Right, 20)
152 .build_cartesian_2d(0..10, 0..10)
153 .expect("Create chart")
154 .set_secondary_coord(0.0..1.0, 0.0..1.0);
155
156 chart
157 .configure_mesh()
158 .x_desc("X")
159 .y_desc("Y")
160 .draw()
161 .expect("Draw mesh");
162 chart
163 .configure_secondary_axes()
164 .x_desc("X")
165 .y_desc("Y")
166 .draw()
167 .expect("Draw Secondary axes");
168
169 let cs = chart.into_chart_state();
171 let mut chart = cs.clone().restore(&drawing_area);
172
173 chart
174 .draw_series(std::iter::once(Circle::new((5, 5), 5, RED)))
175 .expect("Drawing error");
176 chart
177 .draw_secondary_series(std::iter::once(Circle::new((0.3, 0.8), 5, GREEN)))
178 .expect("Drawing error")
179 .label("Test label")
180 .legend(|(x, y)| Rectangle::new([(x - 10, y - 5), (x, y + 5)], GREEN));
181
182 chart
183 .configure_series_labels()
184 .position(SeriesLabelPosition::UpperMiddle)
185 .draw()
186 .expect("Drawing error");
187 }
188
189 #[test]
190 fn test_chart_context_3d() {
191 let drawing_area = create_mocked_drawing_area(200, 200, |_| {});
192
193 drawing_area.fill(&WHITE).expect("Fill");
194
195 let mut chart = ChartBuilder::on(&drawing_area)
196 .caption("Test Title", ("serif", 10))
197 .x_label_area_size(20)
198 .y_label_area_size(20)
199 .set_label_area_size(LabelAreaPosition::Top, 20)
200 .set_label_area_size(LabelAreaPosition::Right, 20)
201 .build_cartesian_3d(0..10, 0..10, 0..10)
202 .expect("Create chart");
203
204 chart.with_projection(|mut pb| {
205 pb.yaw = 0.5;
206 pb.pitch = 0.5;
207 pb.scale = 0.5;
208 pb.into_matrix()
209 });
210
211 chart.configure_axes().draw().expect("Drawing axes");
212
213 let cs = chart.into_chart_state();
215 let mut chart = cs.clone().restore(&drawing_area);
216
217 chart
218 .draw_series(std::iter::once(Circle::new((5, 5, 5), 5, RED)))
219 .expect("Drawing error");
220 }
221}