plotters_iced/
chart.rs

1// plotters-iced
2//
3// Iced backend for Plotters
4// Copyright: 2022, Joylei <leingliu@gmail.com>
5// License: MIT
6
7use iced_widget::canvas::Cache;
8use iced_widget::core::event::Status;
9use iced_widget::core::mouse::Interaction;
10use iced_widget::core::Rectangle;
11use iced_widget::{
12    canvas::{Event, Frame, Geometry},
13    core::{mouse::Cursor, Size},
14};
15use plotters::{chart::ChartBuilder, coord::Shift, drawing::DrawingArea};
16use plotters_backend::DrawingBackend;
17
18/// graphics renderer
19pub trait Renderer {
20    /// draw frame
21    fn draw<F: Fn(&mut Frame)>(&self, bounds: Size, draw_fn: F) -> Geometry;
22
23    /// draw frame with cache
24    fn draw_cache<F: Fn(&mut Frame)>(&self, cache: &Cache, bounds: Size, draw_fn: F) -> Geometry;
25}
26
27impl<Message, C: ?Sized> Chart<Message> for &C
28where
29    C: Chart<Message>,
30{
31    type State = C::State;
32    #[inline]
33    fn build_chart<DB: DrawingBackend>(&self, state: &Self::State, builder: ChartBuilder<DB>) {
34        C::build_chart(self, state, builder);
35    }
36    #[inline]
37    fn draw_chart<DB: DrawingBackend>(&self, state: &Self::State, root: DrawingArea<DB, Shift>) {
38        C::draw_chart(self, state, root);
39    }
40    #[inline]
41    fn draw<R: Renderer, F: Fn(&mut Frame)>(&self, renderer: &R, size: Size, f: F) -> Geometry {
42        C::draw(self, renderer, size, f)
43    }
44    #[inline]
45    fn update(
46        &self,
47        state: &mut Self::State,
48        event: Event,
49        bounds: Rectangle,
50        cursor: Cursor,
51    ) -> (Status, Option<Message>) {
52        C::update(self, state, event, bounds, cursor)
53    }
54    #[inline]
55    fn mouse_interaction(
56        &self,
57        state: &Self::State,
58        bounds: Rectangle,
59        cursor: Cursor,
60    ) -> Interaction {
61        C::mouse_interaction(self, state, bounds, cursor)
62    }
63}
64
65/// Chart View Model
66///
67/// ## Example
68/// ```rust,ignore
69/// use plotters::prelude::*;
70/// use plotters_iced::{Chart,ChartWidget};
71/// struct MyChart;
72/// impl Chart<Message> for MyChart {
73///     type State = ();
74///     fn build_chart<DB:DrawingBackend>(&self, state: &Self::State, builder: ChartBuilder<DB>) {
75///         //build your chart here, please refer to plotters for more details
76///     }
77/// }
78///
79/// impl MyChart {
80///     fn view(&mut self)->Element<Message> {
81///         ChartWidget::new(self)
82///             .width(Length::Fixed(200))
83///             .height(Length::Fixed(200))
84///             .into()
85///     }
86/// }
87/// ```
88pub trait Chart<Message> {
89    /// state data of chart
90    type State: Default + 'static;
91
92    /// draw chart with [`ChartBuilder`]
93    ///
94    /// for simple chart, you impl this method
95    fn build_chart<DB: DrawingBackend>(&self, state: &Self::State, builder: ChartBuilder<DB>);
96
97    /// override this method if you want more freedom of drawing area
98    ///
99    /// ## Example
100    /// ```rust,ignore
101    /// use plotters::prelude::*;
102    /// use plotters_iced::{Chart,ChartWidget};
103    ///
104    /// struct MyChart{}
105    ///
106    /// impl Chart<Message> for MyChart {
107    ///     // leave it empty
108    ///     fn build_chart<DB: DrawingBackend>(&self, state: &Self::State, builder: ChartBuilder<DB>){}
109    ///     fn draw_chart<DB: DrawingBackend>(&self, state: &Self::State, root: DrawingArea<DB, Shift>){
110    ///          let children = root.split_evenly((3,3));
111    ///          for (area, color) in children.into_iter().zip(0..) {
112    ///                area.fill(&Palette99::pick(color)).unwrap();
113    ///          }
114    ///      }
115    /// }
116    /// ```
117    #[inline]
118    fn draw_chart<DB: DrawingBackend>(&self, state: &Self::State, root: DrawingArea<DB, Shift>) {
119        let builder = ChartBuilder::on(&root);
120        self.build_chart(state, builder);
121    }
122
123    /// draw on [`iced_widget::canvas::Canvas`]
124    ///
125    /// override this method if you want to use [`iced_widget::canvas::Cache`]
126    ///
127    /// ## Example
128    /// ```rust,ignore
129    ///
130    /// impl Chart<Message> for CpuUsageChart {
131    ///
132    ///       #[inline]
133    ///       fn draw<R: Renderer, F: Fn(&mut Frame)>(&self, renderer: &R, bounds: Size, draw_fn: F) -> Geometry {
134    ///            R::draw_cache(renderer, &self.cache, size, draw_fn)
135    ///       }
136    ///      //...
137    /// }
138    /// ```
139    #[inline]
140    fn draw<R: Renderer, F: Fn(&mut Frame)>(&self, renderer: &R, size: Size, f: F) -> Geometry {
141        R::draw(renderer, size, f)
142    }
143
144    /// react on event
145    #[allow(unused_variables)]
146    #[inline]
147    #[allow(unused)]
148    fn update(
149        &self,
150        state: &mut Self::State,
151        event: Event,
152        bounds: Rectangle,
153        cursor: Cursor,
154    ) -> (Status, Option<Message>) {
155        (Status::Ignored, None)
156    }
157
158    /// Returns the current mouse interaction of the [`Chart`]
159    #[inline]
160    #[allow(unused)]
161    fn mouse_interaction(
162        &self,
163        state: &Self::State,
164        bounds: Rectangle,
165        cursor: Cursor,
166    ) -> Interaction {
167        Interaction::Idle
168    }
169}