plotters/series/
line_series.rs

1use crate::element::{Circle, DynElement, IntoDynElement, PathElement};
2use crate::style::ShapeStyle;
3use plotters_backend::DrawingBackend;
4use 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
8pub 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
16impl<DB: DrawingBackend, Coord: Clone + 'static> Iterator for LineSeries<DB, Coord> {
17    type Item = DynElement<'static, DB, Coord>;
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
37impl<DB: DrawingBackend, Coord> LineSeries<DB, Coord> {
38    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
48    pub fn point_size(mut self, size: u32) -> Self {
49        self.point_size = size;
50        self
51    }
52}
53
54#[cfg(test)]
55mod test {
56    use crate::prelude::*;
57
58    #[test]
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}