Skip to content

Commit 5b7bce5

Browse files
committed
initial commit
0 parents  commit 5b7bce5

3 files changed

Lines changed: 170 additions & 0 deletions

File tree

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/target
2+
**/*.rs.bk
3+
Cargo.lock
4+
.*.sw*
5+
backup/*
6+
**/Cargo.lock
7+
**/target
8+
examples/wasm-demo/www/pkg
9+
examples/.ipynb_checkpoints/
10+
tarpaulin-report.html
11+
.vscode/*

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "plotters-text"
3+
version = "0.1.0"
4+
authors = ["Hao Hou <haohou302@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
plotters-backend = "^0.0.*"

src/lib.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use plotters_backend::text_anchor::{HPos, VPos};
2+
use plotters_backend::{
3+
BackendColor, BackendStyle, BackendTextStyle, DrawingBackend, DrawingErrorKind,
4+
};
5+
6+
#[derive(Copy, Clone)]
7+
enum PixelState {
8+
Empty,
9+
HLine,
10+
VLine,
11+
Cross,
12+
Pixel,
13+
Text(char),
14+
Circle(bool),
15+
}
16+
17+
impl PixelState {
18+
fn to_char(self) -> char {
19+
match self {
20+
Self::Empty => ' ',
21+
Self::HLine => '-',
22+
Self::VLine => '|',
23+
Self::Cross => '+',
24+
Self::Pixel => '.',
25+
Self::Text(c) => c,
26+
Self::Circle(filled) => {
27+
if filled {
28+
'@'
29+
} else {
30+
'O'
31+
}
32+
}
33+
}
34+
}
35+
36+
fn update(&mut self, new_state: PixelState) {
37+
let next_state = match (*self, new_state) {
38+
(Self::HLine, Self::VLine) => Self::Cross,
39+
(Self::VLine, Self::HLine) => Self::Cross,
40+
(_, Self::Circle(what)) => Self::Circle(what),
41+
(Self::Circle(what), _) => Self::Circle(what),
42+
(_, Self::Pixel) => Self::Pixel,
43+
(Self::Pixel, _) => Self::Pixel,
44+
(_, new) => new,
45+
};
46+
47+
*self = next_state;
48+
}
49+
}
50+
51+
pub struct TextDrawingBackend(Vec<PixelState>);
52+
53+
impl DrawingBackend for TextDrawingBackend {
54+
type ErrorType = std::io::Error;
55+
56+
fn get_size(&self) -> (u32, u32) {
57+
(100, 30)
58+
}
59+
60+
fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
61+
Ok(())
62+
}
63+
64+
fn present(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
65+
for r in 0..30 {
66+
let mut buf = String::new();
67+
for c in 0..100 {
68+
buf.push(self.0[r * 100 + c].to_char());
69+
}
70+
println!("{}", buf);
71+
}
72+
73+
Ok(())
74+
}
75+
76+
fn draw_pixel(
77+
&mut self,
78+
pos: (i32, i32),
79+
color: BackendColor,
80+
) -> Result<(), DrawingErrorKind<std::io::Error>> {
81+
if color.alpha > 0.3 {
82+
self.0[(pos.1 * 100 + pos.0) as usize].update(PixelState::Pixel);
83+
}
84+
Ok(())
85+
}
86+
87+
fn draw_line<S: BackendStyle>(
88+
&mut self,
89+
from: (i32, i32),
90+
to: (i32, i32),
91+
style: &S,
92+
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
93+
if from.0 == to.0 {
94+
let x = from.0;
95+
let y0 = from.1.min(to.1);
96+
let y1 = from.1.max(to.1);
97+
for y in y0..y1 {
98+
self.0[(y * 100 + x) as usize].update(PixelState::VLine);
99+
}
100+
return Ok(());
101+
}
102+
103+
if from.1 == to.1 {
104+
let y = from.1;
105+
let x0 = from.0.min(to.0);
106+
let x1 = from.0.max(to.0);
107+
for x in x0..x1 {
108+
self.0[(y * 100 + x) as usize].update(PixelState::HLine);
109+
}
110+
return Ok(());
111+
}
112+
113+
plotters_backend::rasterizer::draw_line(self, from, to, style)
114+
}
115+
116+
fn estimate_text_size<S: BackendTextStyle>(
117+
&self,
118+
text: &str,
119+
_: &S,
120+
) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
121+
Ok((text.len() as u32, 1))
122+
}
123+
124+
fn draw_text<S: BackendTextStyle>(
125+
&mut self,
126+
text: &str,
127+
style: &S,
128+
pos: (i32, i32),
129+
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
130+
let (width, height) = self.estimate_text_size(text, style)?;
131+
let (width, height) = (width as i32, height as i32);
132+
let dx = match style.anchor().h_pos {
133+
HPos::Left => 0,
134+
HPos::Right => -width,
135+
HPos::Center => -width / 2,
136+
};
137+
let dy = match style.anchor().v_pos {
138+
VPos::Top => 0,
139+
VPos::Center => -height / 2,
140+
VPos::Bottom => -height,
141+
};
142+
let offset = (pos.1 + dy).max(0) * 100 + (pos.0 + dx).max(0);
143+
for (idx, chr) in (offset..).zip(text.chars()) {
144+
self.0[idx as usize].update(PixelState::Text(chr));
145+
}
146+
Ok(())
147+
}
148+
}
149+

0 commit comments

Comments
 (0)