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 /// The line series object, which takes an iterator of points in guest coordinate system
7 /// and creates the element rendering the line plot
8 pub struct LineSeries<DB: DrawingBackend, Coord> {
9     style: ShapeStyle,
10     data: Vec<Coord>,
11     point_idx: usize,
12     point_size: u32,
13     phantom: PhantomData<DB>,
14 }
15 
16 impl<DB: DrawingBackend, Coord: Clone + 'static> Iterator for LineSeries<DB, Coord> {
17     type Item = DynElement<'static, DB, Coord>;
next(&mut self) -> Option<Self::Item>18     fn next(&mut self) -> Option<Self::Item> {
19         if !self.data.is_empty() {
20             if self.point_size > 0 && self.point_idx < self.data.len() {
21                 let idx = self.point_idx;
22                 self.point_idx += 1;
23                 return Some(
24                     Circle::new(self.data[idx].clone(), self.point_size, self.style.clone())
25                         .into_dyn(),
26                 );
27             }
28             let mut data = vec![];
29             std::mem::swap(&mut self.data, &mut data);
30             Some(PathElement::new(data, self.style.clone()).into_dyn())
31         } else {
32             None
33         }
34     }
35 }
36 
37 impl<DB: DrawingBackend, Coord> LineSeries<DB, Coord> {
new<I: IntoIterator<Item = Coord>, S: Into<ShapeStyle>>(iter: I, style: S) -> Self38     pub fn new<I: IntoIterator<Item = Coord>, S: Into<ShapeStyle>>(iter: I, style: S) -> Self {
39         Self {
40             style: style.into(),
41             data: iter.into_iter().collect(),
42             point_size: 0,
43             point_idx: 0,
44             phantom: PhantomData,
45         }
46     }
47 
point_size(mut self, size: u32) -> Self48     pub fn point_size(mut self, size: u32) -> Self {
49         self.point_size = size;
50         self
51     }
52 }
53 
54 #[cfg(test)]
55 mod test {
56     use crate::prelude::*;
57 
58     #[test]
test_line_series()59     fn test_line_series() {
60         let drawing_area = create_mocked_drawing_area(200, 200, |m| {
61             m.check_draw_path(|c, s, path| {
62                 assert_eq!(c, RED.to_rgba());
63                 assert_eq!(s, 3);
64                 for i in 0..100 {
65                     assert_eq!(path[i], (i as i32 * 2, 200 - i as i32 * 2 - 1));
66                 }
67             });
68 
69             m.drop_check(|b| {
70                 assert_eq!(b.num_draw_path_call, 1);
71                 assert_eq!(b.draw_count, 1);
72             });
73         });
74 
75         let mut chart = ChartBuilder::on(&drawing_area)
76             .build_cartesian_2d(0..100, 0..100)
77             .expect("Build chart error");
78 
79         chart
80             .draw_series(LineSeries::new(
81                 (0..100).map(|x| (x, x)),
82                 Into::<ShapeStyle>::into(&RED).stroke_width(3),
83             ))
84             .expect("Drawing Error");
85     }
86 }
87