about summary refs log tree commit diff
path: root/src/griph/mod.rs
blob: 636ffd9a816229dce1fe871a69e9150bff270404 (plain)
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;
		}
	}
}