1 use std::sync::Arc; 2 3 use super::ChartContext; 4 use crate::coord::{CoordTranslate, Shift}; 5 use crate::drawing::DrawingArea; 6 use 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)] 35 pub struct ChartState<CT: CoordTranslate> { 36 drawing_area_pos: (i32, i32), 37 drawing_area_size: (u32, u32), 38 coord: CT, 39 } 40 41 impl<'a, DB: DrawingBackend, CT: CoordTranslate> From<ChartContext<'a, DB, CT>> for ChartState<CT> { from(chart: ChartContext<'a, DB, CT>) -> 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 51 impl<'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. into_chart_state(self) -> ChartState<CT>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 into_shared_chart_state(self) -> ChartState<Arc<CT>>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 71 impl<'a, DB, CT> From<&ChartContext<'a, DB, CT>> for ChartState<CT> 72 where 73 DB: DrawingBackend, 74 CT: CoordTranslate + Clone, 75 { from(chart: &ChartContext<'a, DB, CT>) -> ChartState<CT>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 85 impl<'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 to_chart_state(&self) -> ChartState<CT>87 pub fn to_chart_state(&self) -> ChartState<CT> { 88 self.into() 89 } 90 } 91 92 impl<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 restore<'a, DB: DrawingBackend>( self, area: &DrawingArea<DB, Shift>, ) -> ChartContext<'a, DB, CT>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 } 113