plotters/chart/
state.rs

1use std::sync::Arc;
2
3use super::ChartContext;
4use crate::coord::{CoordTranslate, Shift};
5use crate::drawing::DrawingArea;
6use plotters_backend::DrawingBackend;
7
8/// A chart context state - This is the data that is needed to reconstruct the chart context
9/// without actually drawing the chart. This is useful when we want to do realtime rendering and
10/// want to incrementally update the chart.
11///
12/// For each frame, instead of updating the entire backend, we are able to keep the keep the figure
13/// component like axis, labels untouched and make updates only in the plotting drawing area.
14/// This is very useful for incremental render.
15/// ```rust
16///   use plotters::prelude::*;
17///    let mut buffer = vec![0u8;1024*768*3];
18///    let area = BitMapBackend::with_buffer(&mut buffer[..], (1024, 768))
19///        .into_drawing_area()
20///        .split_evenly((1,2));
21///    let chart = ChartBuilder::on(&area[0])
22///        .caption("Incremental Example", ("sans-serif", 20))
23///        .set_all_label_area_size(30)
24///        .build_cartesian_2d(0..10, 0..10)
25///        .expect("Unable to build ChartContext");
26///    // Draw the first frame at this point
27///    area[0].present().expect("Present");
28///    let state = chart.into_chart_state();
29///    // Let's draw the second frame
30///    let chart = state.restore(&area[0]);
31///    chart.plotting_area().fill(&WHITE).unwrap(); // Clear the previously drawn graph
32///    // At this point, you are able to draw next frame
33///```
34#[derive(Clone)]
35pub struct ChartState<CT: CoordTranslate> {
36    drawing_area_pos: (i32, i32),
37    drawing_area_size: (u32, u32),
38    coord: CT,
39}
40
41impl<'a, DB: DrawingBackend, CT: CoordTranslate> From<ChartContext<'a, DB, CT>> for ChartState<CT> {
42    fn from(chart: ChartContext<'a, DB, CT>) -> ChartState<CT> {
43        ChartState {
44            drawing_area_pos: chart.drawing_area_pos,
45            drawing_area_size: chart.drawing_area.dim_in_pixel(),
46            coord: chart.drawing_area.into_coord_spec(),
47        }
48    }
49}
50
51impl<'a, DB: DrawingBackend, CT: CoordTranslate> ChartContext<'a, DB, CT> {
52    /// Convert a chart context into a chart state, by doing so, the chart context is consumed and
53    /// a saved chart state is created for later use. This is typically used in incrmental rendering. See documentation of `ChartState` for more detailed example.
54    pub fn into_chart_state(self) -> ChartState<CT> {
55        self.into()
56    }
57
58    /// Convert the chart context into a sharable chart state.
59    /// Normally a chart state can not be clone, since the coordinate spec may not be able to be
60    /// cloned. In this case, we can use an `Arc` get the coordinate wrapped thus the state can be
61    /// cloned and shared by multiple chart context
62    pub fn into_shared_chart_state(self) -> ChartState<Arc<CT>> {
63        ChartState {
64            drawing_area_pos: self.drawing_area_pos,
65            drawing_area_size: self.drawing_area.dim_in_pixel(),
66            coord: Arc::new(self.drawing_area.into_coord_spec()),
67        }
68    }
69}
70
71impl<'a, 'b, DB, CT> From<&ChartContext<'a, DB, CT>> for ChartState<CT>
72where
73    DB: DrawingBackend,
74    CT: CoordTranslate + Clone,
75{
76    fn from(chart: &ChartContext<'a, DB, CT>) -> ChartState<CT> {
77        ChartState {
78            drawing_area_pos: chart.drawing_area_pos,
79            drawing_area_size: chart.drawing_area.dim_in_pixel(),
80            coord: chart.drawing_area.as_coord_spec().clone(),
81        }
82    }
83}
84
85impl<'a, DB: DrawingBackend, CT: CoordTranslate + Clone> ChartContext<'a, DB, CT> {
86    /// Make the chart context, do not consume the chart context and clone the coordinate spec
87    pub fn to_chart_state(&self) -> ChartState<CT> {
88        self.into()
89    }
90}
91
92impl<CT: CoordTranslate> ChartState<CT> {
93    /// Restore the chart context on the given drawing area
94    ///
95    /// - `area`: The given drawing area where we want to restore the chart context
96    /// - **returns** The newly created chart context
97    pub fn restore<'a, DB: DrawingBackend>(
98        self,
99        area: &DrawingArea<DB, Shift>,
100    ) -> ChartContext<'a, DB, CT> {
101        let area = area
102            .clone()
103            .shrink(self.drawing_area_pos, self.drawing_area_size);
104        ChartContext {
105            x_label_area: [None, None],
106            y_label_area: [None, None],
107            drawing_area: area.apply_coord_spec(self.coord),
108            series_anno: vec![],
109            drawing_area_pos: self.drawing_area_pos,
110        }
111    }
112}