1 use crate::element::{DynElement, IntoDynElement, PathElement, Polygon};
2 use crate::style::colors::TRANSPARENT;
3 use crate::style::ShapeStyle;
4 use plotters_backend::DrawingBackend;
5 
6 /**
7 An area series is similar to a line series but uses a filled polygon.
8 It takes an iterator of data points in guest coordinate system
9 and creates appropriate lines and points with the given style.
10 
11 # Example
12 
13 ```
14 use plotters::prelude::*;
15 let x_values = [0.0f64, 1., 2., 3., 4.];
16 let drawing_area = SVGBackend::new("area_series.svg", (300, 200)).into_drawing_area();
17 drawing_area.fill(&WHITE).unwrap();
18 let mut chart_builder = ChartBuilder::on(&drawing_area);
19 chart_builder.margin(10).set_left_and_bottom_label_area_size(20);
20 let mut chart_context = chart_builder.build_cartesian_2d(0.0..4.0, 0.0..3.0).unwrap();
21 chart_context.configure_mesh().draw().unwrap();
22 chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 0.3 * x)), 0., BLACK.mix(0.2))).unwrap();
23 chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 2.5 - 0.05 * x * x)), 0., RED.mix(0.2))).unwrap();
24 chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 2. - 0.1 * x * x)), 0., BLUE.mix(0.2)).border_style(BLUE)).unwrap();
25 ```
26 
27 The result is a chart with three line series; one of them has a highlighted blue border:
28 
29 ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@b6703f7/apidoc/area_series.svg)
30 */
31 pub struct AreaSeries<DB: DrawingBackend, X: Clone, Y: Clone> {
32     area_style: ShapeStyle,
33     border_style: ShapeStyle,
34     baseline: Y,
35     data: Vec<(X, Y)>,
36     state: u32,
37     _p: std::marker::PhantomData<DB>,
38 }
39 
40 impl<DB: DrawingBackend, X: Clone, Y: Clone> AreaSeries<DB, X, Y> {
41     /**
42     Creates an area series with transparent border.
43 
44     See [`AreaSeries`] for more information and examples.
45     */
new<S: Into<ShapeStyle>, I: IntoIterator<Item = (X, Y)>>( iter: I, baseline: Y, area_style: S, ) -> Self46     pub fn new<S: Into<ShapeStyle>, I: IntoIterator<Item = (X, Y)>>(
47         iter: I,
48         baseline: Y,
49         area_style: S,
50     ) -> Self {
51         Self {
52             area_style: area_style.into(),
53             baseline,
54             data: iter.into_iter().collect(),
55             state: 0,
56             border_style: (&TRANSPARENT).into(),
57             _p: std::marker::PhantomData,
58         }
59     }
60 
61     /**
62     Sets the border style of the area series.
63 
64     See [`AreaSeries`] for more information and examples.
65     */
border_style<S: Into<ShapeStyle>>(mut self, style: S) -> Self66     pub fn border_style<S: Into<ShapeStyle>>(mut self, style: S) -> Self {
67         self.border_style = style.into();
68         self
69     }
70 }
71 
72 impl<DB: DrawingBackend, X: Clone + 'static, Y: Clone + 'static> Iterator for AreaSeries<DB, X, Y> {
73     type Item = DynElement<'static, DB, (X, Y)>;
next(&mut self) -> Option<Self::Item>74     fn next(&mut self) -> Option<Self::Item> {
75         if self.state == 0 {
76             let mut data: Vec<_> = self.data.clone();
77 
78             if !data.is_empty() {
79                 data.push((data[data.len() - 1].0.clone(), self.baseline.clone()));
80                 data.push((data[0].0.clone(), self.baseline.clone()));
81             }
82 
83             self.state = 1;
84 
85             Some(Polygon::new(data, self.area_style).into_dyn())
86         } else if self.state == 1 {
87             let data: Vec<_> = self.data.clone();
88 
89             self.state = 2;
90 
91             Some(PathElement::new(data, self.border_style).into_dyn())
92         } else {
93             None
94         }
95     }
96 }
97