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
|
use crate::vertex::Vertex;
#[derive(Clone)]
pub struct SubView {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
pub struct GraphView {
pub viewport: SubView,
pub lines: Vec<Vec<Vertex>>,
pub show_grid: bool,
pub title: String,
pub x_axis_label: String,
pub y_axis_label: String,
pub legend_items: Vec<LegendItem>,
}
#[derive(Clone)]
pub struct LegendItem {
pub label: String,
pub color: [f32; 3],
}
impl GraphView {
pub fn new(viewport: SubView, title: String, x_axis_label: String, y_axis_label: String) -> Self {
Self {
viewport,
lines: Vec::new(),
show_grid: true,
title,
x_axis_label,
y_axis_label,
legend_items: Vec::new(),
}
}
pub fn add_legend_item(&mut self, label: String, color: [f32; 3]) {
self.legend_items.push(LegendItem { label, color });
}
pub fn generate_grid_lines(&self) -> Vec<Vertex> {
let mut vertices = Vec::new();
let grid_color = [0.3, 0.7, 0.9];
// Vertical grid lines (10 divisions)
for i in 0..=10 {
let x = -1.0 + (i as f32 / 10.0) * 2.0;
vertices.push(Vertex { position: [x, -1.0], color: grid_color });
vertices.push(Vertex { position: [x, 1.0], color: grid_color });
}
// Horizontal grid lines (10 divisions)
for i in 0..=10 {
let y = -1.0 + (i as f32 / 10.0) * 2.0;
vertices.push(Vertex { position: [-1.0, y], color: grid_color });
vertices.push(Vertex { position: [1.0, y], color: grid_color });
}
vertices
}
pub fn generate_border(&self) -> Vec<Vertex> {
let border_color = [0.6, 0.7, 0.7];
vec![
// Top border
Vertex { position: [-1.0, 1.0], color: border_color },
Vertex { position: [1.0, 1.0], color: border_color },
// Right border
Vertex { position: [1.0, 1.0], color: border_color },
Vertex { position: [1.0, -1.0], color: border_color },
// Bottom border
Vertex { position: [1.0, -1.0], color: border_color },
Vertex { position: [-1.0, -1.0], color: border_color },
// Left border
Vertex { position: [-1.0, -1.0], color: border_color },
Vertex { position: [-1.0, 1.0], color: border_color },
]
}
pub fn update(&mut self, time: f32, graph_idx: usize) {
// Add new line every 10 frames
if (time * 60.0) as u32 % 10 == 0 && self.lines.len() < 50 {
let mut line = Vec::new();
let phase = time + (graph_idx as f32 * 2.0);
let freq = 2.0 + (time * 0.5 + graph_idx as f32).sin() * 1.0;
for i in 0..100 {
let x = (i as f32 / 100.0) * 2.0 - 1.0;
let y = ((i as f32) * 0.1 * freq + phase).sin() * 0.3;
// Different color per graph
let hue = (time * 0.1 + graph_idx as f32 * 0.5) % 1.0;
let color = [
(hue * 6.0).sin().abs(),
((hue + 0.33) * 6.0).sin().abs(),
((hue + 0.66) * 6.0).sin().abs(),
];
line.push(Vertex {
position: [x, y],
color,
});
}
self.lines.push(line);
}
// Scroll lines down
for line in self.lines.iter_mut() {
for vertex in line.iter_mut() {
vertex.position[1] -= 0.01;
}
}
// Remove lines that have scrolled off screen
self.lines.retain(|line| {
line.first().map(|v| v.position[1] > -1.1).unwrap_or(false)
});
}
}
|