1 use crate::element::{Circle, DynElement, IntoDynElement, PathElement};
2 use crate::style::ShapeStyle;
3 use plotters_backend::DrawingBackend;
4 use std::marker::PhantomData;
5 
6 /**
7 The line series object, which takes an iterator of data points in guest coordinate system
8 and creates appropriate lines and points with the given style.
9 
10 # Example
11 
12 ```
13 use plotters::prelude::*;
14 let x_values = [0.0f64, 1., 2., 3., 4.];
15 let drawing_area = SVGBackend::new("line_series_point_size.svg", (300, 200)).into_drawing_area();
16 drawing_area.fill(&WHITE).unwrap();
17 let mut chart_builder = ChartBuilder::on(&drawing_area);
18 chart_builder.margin(10).set_left_and_bottom_label_area_size(20);
19 let mut chart_context = chart_builder.build_cartesian_2d(0.0..4.0, 0.0..3.0).unwrap();
20 chart_context.configure_mesh().draw().unwrap();
21 chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 0.3 * x)), BLACK)).unwrap();
22 chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 2.5 - 0.05 * x * x)), RED)
23     .point_size(5)).unwrap();
24 chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 2. - 0.1 * x * x)), BLUE.filled())
25     .point_size(4)).unwrap();
26 ```
27 
28 The result is a chart with three line series; two of them have their data points highlighted:
29 
30 ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@64e0a28/apidoc/line_series_point_size.svg)
31 */
32 pub struct LineSeries<DB: DrawingBackend, Coord> {
33     style: ShapeStyle,
34     data: Vec<Coord>,
35     point_idx: usize,
36     point_size: u32,
37     phantom: PhantomData<DB>,
38 }
39 
40 impl<DB: DrawingBackend, Coord: Clone + 'static> Iterator for LineSeries<DB, Coord> {
41     type Item = DynElement<'static, DB, Coord>;
next(&mut self) -> Option<Self::Item>42     fn next(&mut self) -> Option<Self::Item> {
43         if !self.data.is_empty() {
44             if self.point_size > 0 && self.point_idx < self.data.len() {
45                 let idx = self.point_idx;
46                 self.point_idx += 1;
47                 return Some(
48                     Circle::new(self.data[idx].clone(), self.point_size, self.style).into_dyn(),
49                 );
50             }
51             let mut data = vec![];
52             std::mem::swap(&mut self.data, &mut data);
53             Some(PathElement::new(data, self.style).into_dyn())
54         } else {
55             None
56         }
57     }
58 }
59 
60 impl<DB: DrawingBackend, Coord> LineSeries<DB, Coord> {
61     /**
62     Creates a new line series based on a data iterator and a given style.
63 
64     See [`LineSeries`] for more information and examples.
65     */
new<I: IntoIterator<Item = Coord>, S: Into<ShapeStyle>>(iter: I, style: S) -> Self66     pub fn new<I: IntoIterator<Item = Coord>, S: Into<ShapeStyle>>(iter: I, style: S) -> Self {
67         Self {
68             style: style.into(),
69             data: iter.into_iter().collect(),
70             point_size: 0,
71             point_idx: 0,
72             phantom: PhantomData,
73         }
74     }
75 
76     /**
77     Sets the size of the points in the series, in pixels.
78 
79     See [`LineSeries`] for more information and examples.
80     */
point_size(mut self, size: u32) -> Self81     pub fn point_size(mut self, size: u32) -> Self {
82         self.point_size = size;
83         self
84     }
85 }
86 
87 #[cfg(test)]
88 mod test {
89     use crate::prelude::*;
90 
91     #[test]
test_line_series()92     fn test_line_series() {
93         let drawing_area = create_mocked_drawing_area(200, 200, |m| {
94             m.check_draw_path(|c, s, _path| {
95                 assert_eq!(c, RED.to_rgba());
96                 assert_eq!(s, 3);
97                 // TODO when cleanup the backend coordinate defination, then we uncomment the
98                 // following check
99                 //for i in 0..100 {
100                 //    assert_eq!(path[i], (i as i32 * 2, 199 - i as i32 * 2));
101                 //}
102             });
103 
104             m.drop_check(|b| {
105                 assert_eq!(b.num_draw_path_call, 1);
106                 assert_eq!(b.draw_count, 1);
107             });
108         });
109 
110         let mut chart = ChartBuilder::on(&drawing_area)
111             .build_cartesian_2d(0..100, 0..100)
112             .expect("Build chart error");
113 
114         chart
115             .draw_series(LineSeries::new(
116                 (0..100).map(|x| (x, x)),
117                 Into::<ShapeStyle>::into(&RED).stroke_width(3),
118             ))
119             .expect("Drawing Error");
120     }
121 }
122