11use std:: borrow:: Borrow ;
2- use std:: marker:: PhantomData ;
32use std:: ops:: Range ;
4- use std:: sync:: Arc ;
53
6- use super :: dual_coord:: DualCoordChartContext ;
7- use super :: mesh:: MeshStyle ;
8- use super :: series:: SeriesLabelStyle ;
4+ use super :: { DualCoordChartContext , MeshStyle , SeriesAnno , SeriesLabelStyle } ;
95
106use crate :: coord:: {
117 AsRangedCoord , CoordTranslate , KeyPointHint , MeshLine , Ranged , RangedCoord ,
128 ReverseCoordTranslate , Shift , ValueFormatter ,
139} ;
1410use crate :: drawing:: { DrawingArea , DrawingAreaErrorKind } ;
15- use crate :: element:: { Drawable , DynElement , IntoDynElement , PathElement , PointCollection } ;
11+ use crate :: element:: { Drawable , PathElement , PointCollection } ;
1612use crate :: style:: text_anchor:: { HPos , Pos , VPos } ;
17- use crate :: style:: { AsRelative , ShapeStyle , SizeDesc , TextStyle } ;
13+ use crate :: style:: { ShapeStyle , TextStyle } ;
1814
1915use plotters_backend:: { BackendCoord , DrawingBackend , FontTransform } ;
2016
21- /// The annotations (such as the label of the series, the legend element, etc)
22- /// When a series is drawn onto a drawing area, an series annotation object
23- /// is created and a mutable reference is returned.
24- #[ allow( clippy:: type_complexity) ]
25- pub struct SeriesAnno < ' a , DB : DrawingBackend > {
26- label : Option < String > ,
27- draw_func : Option < Box < dyn Fn ( BackendCoord ) -> DynElement < ' a , DB , BackendCoord > + ' a > > ,
28- phantom_data : PhantomData < DB > ,
29- }
30-
31- impl < ' a , DB : DrawingBackend > SeriesAnno < ' a , DB > {
32- pub ( crate ) fn get_label ( & self ) -> & str {
33- self . label . as_ref ( ) . map ( |x| x. as_str ( ) ) . unwrap_or ( "" )
34- }
35-
36- pub ( crate ) fn get_draw_func (
37- & self ,
38- ) -> Option < & dyn Fn ( BackendCoord ) -> DynElement < ' a , DB , BackendCoord > > {
39- self . draw_func . as_ref ( ) . map ( |x| x. borrow ( ) )
40- }
41-
42- fn new ( ) -> Self {
43- Self {
44- label : None ,
45- draw_func : None ,
46- phantom_data : PhantomData ,
47- }
48- }
49-
50- /// Set the series label
51- /// - `label`: The string would be use as label for current series
52- pub fn label < L : Into < String > > ( & mut self , label : L ) -> & mut Self {
53- self . label = Some ( label. into ( ) ) ;
54- self
55- }
56-
57- /// Set the legend element creator function
58- /// - `func`: The function use to create the element
59- /// *Note*: The creation function uses a shifted pixel-based coordinate system. And place the
60- /// point (0,0) to the mid-right point of the shape
61- pub fn legend < E : IntoDynElement < ' a , DB , BackendCoord > , T : Fn ( BackendCoord ) -> E + ' a > (
62- & mut self ,
63- func : T ,
64- ) -> & mut Self {
65- self . draw_func = Some ( Box :: new ( move |p| func ( p) . into_dyn ( ) ) ) ;
66- self
67- }
68- }
69-
7017/// The context of the chart. This is the core object of Plotters.
7118/// Any plot/chart is abstracted as this type, and any data series can be placed to the chart
7219/// context.
20+ ///
21+ /// - To draw a series on a chart context, use [ChartContext::draw_series](struct.ChartContext.html#method.draw_series)
22+ /// - To draw a single element to the chart, you may want to use [ChartContext::plotting_area](struct.ChartContext.html#method.plotting_area)
23+ ///
7324pub struct ChartContext < ' a , DB : DrawingBackend , CT : CoordTranslate > {
7425 pub ( super ) x_label_area : [ Option < DrawingArea < DB , Shift > > ; 2 ] ,
7526 pub ( super ) y_label_area : [ Option < DrawingArea < DB , Shift > > ; 2 ] ,
@@ -78,131 +29,16 @@ pub struct ChartContext<'a, DB: DrawingBackend, CT: CoordTranslate> {
7829 pub ( super ) drawing_area_pos : ( i32 , i32 ) ,
7930}
8031
81- /// A chart context state - This is the data that is needed to reconstruct the chart context
82- /// without actually drawing the chart. This is useful when we want to do realtime rendering and
83- /// want to incrementally update the chart.
84- ///
85- /// For each frame, instead of updating the entire backend, we are able to keep the keep the figure
86- /// component like axis, labels untouched and make updates only in the plotting drawing area.
87- /// This is very useful for incremental render.
88- /// ```rust
89- /// use plotters::prelude::*;
90- /// let mut buffer = vec![0u8;1024*768*3];
91- /// let area = BitMapBackend::with_buffer(&mut buffer[..], (1024, 768))
92- /// .into_drawing_area()
93- /// .split_evenly((1,2));
94- /// let chart = ChartBuilder::on(&area[0])
95- /// .caption("Incremental Example", ("sans-serif", 20))
96- /// .set_all_label_area_size(30)
97- /// .build_ranged(0..10, 0..10)
98- /// .expect("Unable to build ChartContext");
99- /// // Draw the first frame at this point
100- /// area[0].present().expect("Present");
101- /// let state = chart.into_chart_state();
102- /// // Let's draw the second frame
103- /// let chart = state.restore(&area[0]);
104- /// chart.plotting_area().fill(&WHITE).unwrap(); // Clear the previously drawn graph
105- /// // At this point, you are able to draw next frame
106- ///```
107- pub struct ChartState < CT : CoordTranslate > {
108- drawing_area_pos : ( i32 , i32 ) ,
109- drawing_area_size : ( u32 , u32 ) ,
110- coord : CT ,
111- }
112-
113- impl < ' a , CT : CoordTranslate + Clone > Clone for ChartState < CT > {
114- fn clone ( & self ) -> Self {
115- Self {
116- drawing_area_size : self . drawing_area_size ,
117- drawing_area_pos : self . drawing_area_pos ,
118- coord : self . coord . clone ( ) ,
119- }
120- }
121- }
122-
123- impl < ' a , DB : DrawingBackend , CT : CoordTranslate > From < ChartContext < ' a , DB , CT > > for ChartState < CT > {
124- fn from ( chart : ChartContext < ' a , DB , CT > ) -> ChartState < CT > {
125- ChartState {
126- drawing_area_pos : chart. drawing_area_pos ,
127- drawing_area_size : chart. drawing_area . dim_in_pixel ( ) ,
128- coord : chart. drawing_area . into_coord_spec ( ) ,
129- }
130- }
131- }
132-
133- impl < ' a , DB : DrawingBackend , CT : CoordTranslate > ChartContext < ' a , DB , CT > {
134- /// Convert a chart context into a chart state, by doing so, the chart context is consumed and
135- /// a saved chart state is created for later use. This is typically used in incrmental rendering. See documentation of `ChartState` for more detailed example.
136- pub fn into_chart_state ( self ) -> ChartState < CT > {
137- self . into ( )
138- }
139-
140- /// Convert the chart context into a sharable chart state.
141- /// Normally a chart state can not be clone, since the coordinate spec may not be able to be
142- /// cloned. In this case, we can use an `Arc` get the coordinate wrapped thus the state can be
143- /// cloned and shared by multiple chart context
144- pub fn into_shared_chart_state ( self ) -> ChartState < Arc < CT > > {
145- ChartState {
146- drawing_area_pos : self . drawing_area_pos ,
147- drawing_area_size : self . drawing_area . dim_in_pixel ( ) ,
148- coord : Arc :: new ( self . drawing_area . into_coord_spec ( ) ) ,
149- }
150- }
151- }
152-
153- impl < ' a , ' b , DB , CT > From < & ChartContext < ' a , DB , CT > > for ChartState < CT >
32+ impl < ' a , DB , XT , YT , X , Y > ChartContext < ' a , DB , RangedCoord < X , Y > >
15433where
15534 DB : DrawingBackend ,
156- CT : CoordTranslate + Clone ,
157- {
158- fn from ( chart : & ChartContext < ' a , DB , CT > ) -> ChartState < CT > {
159- ChartState {
160- drawing_area_pos : chart. drawing_area_pos ,
161- drawing_area_size : chart. drawing_area . dim_in_pixel ( ) ,
162- coord : chart. drawing_area . as_coord_spec ( ) . clone ( ) ,
163- }
164- }
165- }
166-
167- impl < ' a , DB : DrawingBackend , CT : CoordTranslate + Clone > ChartContext < ' a , DB , CT > {
168- /// Make the chart context, do not consume the chart context and clone the coordinate spec
169- pub fn to_chart_state ( & self ) -> ChartState < CT > {
170- self . into ( )
171- }
172- }
173-
174- impl < CT : CoordTranslate > ChartState < CT > {
175- /// Restore the chart context on the given drawing area
176- ///
177- /// - `area`: The given drawing area where we want to restore the chart context
178- /// - **returns** The newly created chart context
179- pub fn restore < ' a , DB : DrawingBackend > (
180- self ,
181- area : & DrawingArea < DB , Shift > ,
182- ) -> ChartContext < ' a , DB , CT > {
183- let area = area
184- . clone ( )
185- . shrink ( self . drawing_area_pos , self . drawing_area_size ) ;
186- ChartContext {
187- x_label_area : [ None , None ] ,
188- y_label_area : [ None , None ] ,
189- drawing_area : area. apply_coord_spec ( self . coord ) ,
190- series_anno : vec ! [ ] ,
191- drawing_area_pos : self . drawing_area_pos ,
192- }
193- }
194- }
195-
196- impl <
197- ' a ,
198- DB : DrawingBackend ,
199- XT ,
200- YT ,
201- X : Ranged < ValueType = XT > + ValueFormatter < XT > ,
202- Y : Ranged < ValueType = YT > + ValueFormatter < YT > ,
203- > ChartContext < ' a , DB , RangedCoord < X , Y > >
35+ X : Ranged < ValueType = XT > + ValueFormatter < XT > ,
36+ Y : Ranged < ValueType = YT > + ValueFormatter < YT > ,
20437{
205- fn is_overlapping_drawing_area ( & self , area : Option < & DrawingArea < DB , Shift > > ) -> bool {
38+ pub ( crate ) fn is_overlapping_drawing_area (
39+ & self ,
40+ area : Option < & DrawingArea < DB , Shift > > ,
41+ ) -> bool {
20642 if let Some ( area) = area {
20743 let ( x0, y0) = area. get_base_pixel ( ) ;
20844 let ( w, h) = area. dim_in_pixel ( ) ;
@@ -222,52 +58,17 @@ impl<
22258
22359 /// Initialize a mesh configuration object and mesh drawing can be finalized by calling
22460 /// the function `MeshStyle::draw`.
225- pub fn configure_mesh < ' b > ( & ' b mut self ) -> MeshStyle < ' a , ' b , X , Y , DB > {
226- let base_tick_size = ( 5u32 ) . percent ( ) . max ( 5 ) . in_pixels ( & self . drawing_area ) ;
227-
228- let mut x_tick_size = [ base_tick_size, base_tick_size] ;
229- let mut y_tick_size = [ base_tick_size, base_tick_size] ;
230-
231- for idx in 0 ..2 {
232- if self . is_overlapping_drawing_area ( self . x_label_area [ idx] . as_ref ( ) ) {
233- x_tick_size[ idx] = -x_tick_size[ idx] ;
234- }
235- if self . is_overlapping_drawing_area ( self . y_label_area [ idx] . as_ref ( ) ) {
236- y_tick_size[ idx] = -y_tick_size[ idx] ;
237- }
238- }
239-
240- MeshStyle {
241- parent_size : self . drawing_area . dim_in_pixel ( ) ,
242- axis_style : None ,
243- x_label_offset : 0 ,
244- y_label_offset : 0 ,
245- draw_x_mesh : true ,
246- draw_y_mesh : true ,
247- draw_x_axis : true ,
248- draw_y_axis : true ,
249- n_x_labels : 10 ,
250- n_y_labels : 10 ,
251- bold_line_style : None ,
252- light_line_style : None ,
253- x_label_style : None ,
254- y_label_style : None ,
255- format_x : & X :: format,
256- format_y : & Y :: format,
257- target : Some ( self ) ,
258- _phantom_data : PhantomData ,
259- x_desc : None ,
260- y_desc : None ,
261- axis_desc_style : None ,
262- x_tick_size,
263- y_tick_size,
264- }
61+ pub fn configure_mesh ( & mut self ) -> MeshStyle < ' a , ' _ , X , Y , DB > {
62+ MeshStyle :: new ( self )
26563 }
26664}
26765
268- impl < ' a , DB : DrawingBackend + ' a , CT : CoordTranslate > ChartContext < ' a , DB , CT > {
66+ impl < ' a , DB : DrawingBackend , CT : CoordTranslate > ChartContext < ' a , DB , CT > {
26967 /// Configure the styles for drawing series labels in the chart
270- pub fn configure_series_labels < ' b > ( & ' b mut self ) -> SeriesLabelStyle < ' a , ' b , DB , CT > {
68+ pub fn configure_series_labels < ' b > ( & ' b mut self ) -> SeriesLabelStyle < ' a , ' b , DB , CT >
69+ where
70+ DB : ' a ,
71+ {
27172 SeriesLabelStyle :: new ( self )
27273 }
27374
@@ -292,18 +93,18 @@ impl<'a, DB: DrawingBackend, CT: ReverseCoordTranslate> ChartContext<'a, DB, CT>
29293 }
29394}
29495
295- impl < ' a , DB : DrawingBackend , X : Ranged , Y : Ranged > ChartContext < ' a , DB , Arc < RangedCoord < X , Y > > > {
296- // TODO: All draw_series_impl is over strict on lifetime, because we don't have stable HKT,
96+ impl < ' a , DB : DrawingBackend , CT : CoordTranslate > ChartContext < ' a , DB , CT > {
97+ // TODO: All draw_series_impl is overly strict about lifetime, because we don't have stable HKT,
29798 // what we can ensure is for all lifetime 'b the element reference &'b E is a iterator
29899 // of points reference with the same lifetime.
299100 // However, this doesn't work if the coordinate doesn't live longer than the backend,
300- // this is unneccessarily strct
101+ // this is unnecessarily strict
301102 pub ( super ) fn draw_series_impl < E , R , S > (
302103 & mut self ,
303104 series : S ,
304105 ) -> Result < ( ) , DrawingAreaErrorKind < DB :: ErrorType > >
305106 where
306- for < ' b > & ' b E : PointCollection < ' b , ( X :: ValueType , Y :: ValueType ) > ,
107+ for < ' b > & ' b E : PointCollection < ' b , CT :: From > ,
307108 E : Drawable < DB > ,
308109 R : Borrow < E > ,
309110 S : IntoIterator < Item = R > ,
@@ -326,7 +127,7 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Arc<Rang
326127 series : S ,
327128 ) -> Result < & mut SeriesAnno < ' a , DB > , DrawingAreaErrorKind < DB :: ErrorType > >
328129 where
329- for < ' b > & ' b E : PointCollection < ' b , ( X :: ValueType , Y :: ValueType ) > ,
130+ for < ' b > & ' b E : PointCollection < ' b , CT :: From > ,
330131 E : Drawable < DB > ,
331132 R : Borrow < E > ,
332133 S : IntoIterator < Item = R > ,
@@ -353,44 +154,6 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, RangedCo
353154 self . drawing_area . map_coordinate ( coord)
354155 }
355156
356- pub ( super ) fn draw_series_impl < E , R , S > (
357- & mut self ,
358- series : S ,
359- ) -> Result < ( ) , DrawingAreaErrorKind < DB :: ErrorType > >
360- where
361- for < ' b > & ' b E : PointCollection < ' b , ( X :: ValueType , Y :: ValueType ) > ,
362- E : Drawable < DB > ,
363- R : Borrow < E > ,
364- S : IntoIterator < Item = R > ,
365- {
366- for element in series {
367- self . drawing_area . draw ( element. borrow ( ) ) ?;
368- }
369- Ok ( ( ) )
370- }
371-
372- pub ( super ) fn alloc_series_anno ( & mut self ) -> & mut SeriesAnno < ' a , DB > {
373- let idx = self . series_anno . len ( ) ;
374- self . series_anno . push ( SeriesAnno :: new ( ) ) ;
375- & mut self . series_anno [ idx]
376- }
377-
378- /// Draw a data series. A data series in Plotters is abstracted as an iterator of elements.
379- /// - **Returns**: Either drawing error or a series annotation object thus we can put annotation to current series (e.g. legend)
380- pub fn draw_series < E , R , S > (
381- & mut self ,
382- series : S ,
383- ) -> Result < & mut SeriesAnno < ' a , DB > , DrawingAreaErrorKind < DB :: ErrorType > >
384- where
385- for < ' b > & ' b E : PointCollection < ' b , ( X :: ValueType , Y :: ValueType ) > ,
386- E : Drawable < DB > ,
387- R : Borrow < E > ,
388- S : IntoIterator < Item = R > ,
389- {
390- self . draw_series_impl ( series) ?;
391- Ok ( self . alloc_series_anno ( ) )
392- }
393-
394157 /// The actual function that draws the mesh lines.
395158 /// It also returns the label that suppose to be there.
396159 #[ allow( clippy:: type_complexity) ]
0 commit comments