summaryrefslogtreecommitdiff
path: root/src/graph.rs
blob: 7426beef5d9001697780193f38b2f7fc5de039ca (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
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)
        });
    }
}