1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
use gifed::{writer::ImageBuilder, Gif, StandardGif};
#[rustfmt::skip]
pub const DARK_PALETTE: &[u8] = &[
0, 0, 0, // Background - Black
192, 192, 192, // Graphline - Mostly White
64, 64, 64, // Gridlines - Dark gray
32, 32, 32, // Minor Gridlines - Darker gray
144, 144, 255, // Primary 2 Colour - Blue
48, 192, 48, // Secondary 2 Colour - Green
96, 96, 224, // Primary Underfill - Light Blue
48, 128, 48, // Secondary Underfill - Lesser Green
144, 144, 144 // Graphline Underfill - 16 * 9 gray
];
const BACKGROUND: u8 = 0;
const LINE: u8 = 1;
const GRIDLINE: u8 = 2;
const MINOR_GRIDLINE: u8 = 3;
const LINE1: u8 = 4;
const LINE2: u8 = 5;
const LINE1_FILL: u8 = 6;
const LINE2_FILL: u8 = 7;
const LINE_FILL: u8 = 8;
const WIDTH: usize = 256;
const HEIGHT: usize = 160;
const SIZE: usize = WIDTH * HEIGHT;
pub enum Style {
Line,
UnderfilledLine,
}
pub fn make_1line(min: usize, max: usize, values: &[Option<usize>], style: Style) -> Gif {
let range = max - min;
// this assumes a range of values that is >1 per pixel
let vpp = range / HEIGHT;
let mut raster = vec![0; SIZE];
let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16);
draw_grid(&mut raster);
draw_line(&mut raster, values, vpp, LINE);
let plt = match style {
Style::Line => {
draw_line(&mut raster, values, vpp, LINE);
&DARK_PALETTE[0..12]
}
Style::UnderfilledLine => {
draw_line_underfill(&mut raster, values, vpp, LINE_FILL, LINE);
&DARK_PALETTE
}
};
standard.set_palette(Some(plt.try_into().unwrap()));
standard.push(
ImageBuilder::new(WIDTH as u16, HEIGHT as u16)
.build(raster)
.unwrap(),
);
standard
}
pub fn make_2line(
min: usize,
max: usize,
values1: &[Option<usize>],
values2: &[Option<usize>],
) -> Gif {
let range = max - min;
// this assumes a range of values that is >1 per pixel
let vpp = range / HEIGHT;
let mut raster = vec![0; SIZE];
draw_grid(&mut raster);
draw_line_underfill(&mut raster, values1, vpp, LINE1, LINE1_FILL);
draw_line_underfill(&mut raster, values2, vpp, LINE2, LINE2_FILL);
let mut standard = Gif::new(WIDTH as u16, HEIGHT as u16);
standard.set_palette(Some(DARK_PALETTE.try_into().unwrap()));
standard.push(
ImageBuilder::new(WIDTH as u16, HEIGHT as u16)
.build(raster)
.unwrap(),
);
standard
}
fn draw_grid(raster: &mut [u8]) {
// Draw Divisions
// we want a gridline every 16 pixels, but not the bottom
// or top, so only 8.
for div in 1..=9 {
let y_val = div * 16;
let grid = if div % 2 == 0 {
GRIDLINE
} else {
MINOR_GRIDLINE
};
for x in 0..WIDTH {
raster[y_val * WIDTH + x] = grid;
}
}
}
fn draw_line(raster: &mut [u8], values: &[Option<usize>], vpp: usize, colour: u8) {
// Draw Line
// this will be discontinuous and i think that's okay. we
// could make it a proper line by keeping track what value
// was last and drawing the whole vertical there
for (x, maybe) in values.iter().enumerate() {
if let Some(value) = maybe {
let value_height = value / vpp;
if value_height > (HEIGHT - 1) {
continue;
}
let y_val = (HEIGHT - 1) - value_height;
raster[y_val * WIDTH + x] = colour;
}
}
}
fn draw_line_underfill(
raster: &mut [u8],
values: &[Option<usize>],
vpp: usize,
colour: u8,
colour_fill: u8,
) {
for (x, maybe) in values.iter().enumerate() {
if let Some(value) = maybe {
let value_height = value / vpp;
if value_height > (HEIGHT - 1) {
continue;
}
let y_val = (HEIGHT - 1) - value_height;
for y in y_val + 1..HEIGHT {
raster[y * WIDTH + x] = colour_fill;
}
raster[y_val * WIDTH + x] = colour;
}
}
}
|