• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use plotters::prelude::*;
2 use plotters::style::text_anchor::{HPos, VPos};
3 use plotters_backend::{
4     BackendColor, BackendStyle, BackendTextStyle, DrawingBackend, DrawingErrorKind,
5 };
6 use std::error::Error;
7 
8 #[derive(Copy, Clone)]
9 enum PixelState {
10     Empty,
11     HLine,
12     VLine,
13     Cross,
14     Pixel,
15     Text(char),
16     Circle(bool),
17 }
18 
19 impl PixelState {
to_char(self) -> char20     fn to_char(self) -> char {
21         match self {
22             Self::Empty => ' ',
23             Self::HLine => '-',
24             Self::VLine => '|',
25             Self::Cross => '+',
26             Self::Pixel => '.',
27             Self::Text(c) => c,
28             Self::Circle(filled) => {
29                 if filled {
30                     '@'
31                 } else {
32                     'O'
33                 }
34             }
35         }
36     }
37 
update(&mut self, new_state: PixelState)38     fn update(&mut self, new_state: PixelState) {
39         let next_state = match (*self, new_state) {
40             (Self::HLine, Self::VLine) => Self::Cross,
41             (Self::VLine, Self::HLine) => Self::Cross,
42             (_, Self::Circle(what)) => Self::Circle(what),
43             (Self::Circle(what), _) => Self::Circle(what),
44             (_, Self::Pixel) => Self::Pixel,
45             (Self::Pixel, _) => Self::Pixel,
46             (_, new) => new,
47         };
48 
49         *self = next_state;
50     }
51 }
52 
53 pub struct TextDrawingBackend(Vec<PixelState>);
54 
55 impl DrawingBackend for TextDrawingBackend {
56     type ErrorType = std::io::Error;
57 
get_size(&self) -> (u32, u32)58     fn get_size(&self) -> (u32, u32) {
59         (100, 30)
60     }
61 
ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>>62     fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
63         Ok(())
64     }
65 
present(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>>66     fn present(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
67         for r in 0..30 {
68             let mut buf = String::new();
69             for c in 0..100 {
70                 buf.push(self.0[r * 100 + c].to_char());
71             }
72             println!("{}", buf);
73         }
74 
75         Ok(())
76     }
77 
draw_pixel( &mut self, pos: (i32, i32), color: BackendColor, ) -> Result<(), DrawingErrorKind<std::io::Error>>78     fn draw_pixel(
79         &mut self,
80         pos: (i32, i32),
81         color: BackendColor,
82     ) -> Result<(), DrawingErrorKind<std::io::Error>> {
83         if color.alpha > 0.3 {
84             self.0[(pos.1 * 100 + pos.0) as usize].update(PixelState::Pixel);
85         }
86         Ok(())
87     }
88 
draw_line<S: BackendStyle>( &mut self, from: (i32, i32), to: (i32, i32), style: &S, ) -> Result<(), DrawingErrorKind<Self::ErrorType>>89     fn draw_line<S: BackendStyle>(
90         &mut self,
91         from: (i32, i32),
92         to: (i32, i32),
93         style: &S,
94     ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
95         if from.0 == to.0 {
96             let x = from.0;
97             let y0 = from.1.min(to.1);
98             let y1 = from.1.max(to.1);
99             for y in y0..y1 {
100                 self.0[(y * 100 + x) as usize].update(PixelState::VLine);
101             }
102             return Ok(());
103         }
104 
105         if from.1 == to.1 {
106             let y = from.1;
107             let x0 = from.0.min(to.0);
108             let x1 = from.0.max(to.0);
109             for x in x0..x1 {
110                 self.0[(y * 100 + x) as usize].update(PixelState::HLine);
111             }
112             return Ok(());
113         }
114 
115         plotters_backend::rasterizer::draw_line(self, from, to, style)
116     }
117 
estimate_text_size<S: BackendTextStyle>( &self, text: &str, _: &S, ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>>118     fn estimate_text_size<S: BackendTextStyle>(
119         &self,
120         text: &str,
121         _: &S,
122     ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
123         Ok((text.len() as u32, 1))
124     }
125 
draw_text<S: BackendTextStyle>( &mut self, text: &str, style: &S, pos: (i32, i32), ) -> Result<(), DrawingErrorKind<Self::ErrorType>>126     fn draw_text<S: BackendTextStyle>(
127         &mut self,
128         text: &str,
129         style: &S,
130         pos: (i32, i32),
131     ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
132         let (width, height) = self.estimate_text_size(text, style)?;
133         let (width, height) = (width as i32, height as i32);
134         let dx = match style.anchor().h_pos {
135             HPos::Left => 0,
136             HPos::Right => -width,
137             HPos::Center => -width / 2,
138         };
139         let dy = match style.anchor().v_pos {
140             VPos::Top => 0,
141             VPos::Center => -height / 2,
142             VPos::Bottom => -height,
143         };
144         let offset = (pos.1 + dy).max(0) * 100 + (pos.0 + dx).max(0);
145         for (idx, chr) in (offset..).zip(text.chars()) {
146             self.0[idx as usize].update(PixelState::Text(chr));
147         }
148         Ok(())
149     }
150 }
151 
draw_chart<DB: DrawingBackend>( b: DrawingArea<DB, plotters::coord::Shift>, ) -> Result<(), Box<dyn Error>> where DB::ErrorType: 'static,152 fn draw_chart<DB: DrawingBackend>(
153     b: DrawingArea<DB, plotters::coord::Shift>,
154 ) -> Result<(), Box<dyn Error>>
155 where
156     DB::ErrorType: 'static,
157 {
158     let mut chart = ChartBuilder::on(&b)
159         .margin(1)
160         .caption("Sine and Cosine", ("sans-serif", (10).percent_height()))
161         .set_label_area_size(LabelAreaPosition::Left, (5i32).percent_width())
162         .set_label_area_size(LabelAreaPosition::Bottom, (10i32).percent_height())
163         .build_cartesian_2d(-std::f64::consts::PI..std::f64::consts::PI, -1.2..1.2)?;
164 
165     chart
166         .configure_mesh()
167         .disable_x_mesh()
168         .disable_y_mesh()
169         .draw()?;
170 
171     chart.draw_series(LineSeries::new(
172         (-314..314).map(|x| x as f64 / 100.0).map(|x| (x, x.sin())),
173         &RED,
174     ))?;
175 
176     chart.draw_series(LineSeries::new(
177         (-314..314).map(|x| x as f64 / 100.0).map(|x| (x, x.cos())),
178         &RED,
179     ))?;
180 
181     b.present()?;
182 
183     Ok(())
184 }
185 
main() -> Result<(), Box<dyn Error>>186 fn main() -> Result<(), Box<dyn Error>> {
187     draw_chart(TextDrawingBackend(vec![PixelState::Empty; 5000]).into_drawing_area())?;
188     let b = BitMapBackend::new("plotters-doc-data/console-example.png", (1024, 768))
189         .into_drawing_area();
190     b.fill(&WHITE)?;
191     draw_chart(b)?;
192     Ok(())
193 }
194 #[test]
entry_point()195 fn entry_point() {
196     main().unwrap()
197 }
198