use crossterm::event::{KeyEvent, MouseEvent};
use ratatui::{
layout::Rect,
style::{Color, Style},
symbols,
text::Span,
widgets::{Axis, Block, BorderType, Borders, Chart, Dataset, GraphType},
Frame,
};
use crate::widget::Widget;
pub struct EventsGraphWidget {
pub id: u8,
pub title: &'static str,
pub events_per_sec: usize,
pub snapshots: Vec<(f64, f64)>, pub area: Option<Rect>,
pub focused: bool,
pub tick: f64,
}
impl EventsGraphWidget {
pub fn new() -> Self {
Self {
id: 3,
title: "~ Events Graph ~",
events_per_sec: 0,
snapshots: vec![],
area: None,
focused: false,
tick: 0.0,
}
}
pub fn on_tick(&mut self, events_per_sec: usize) {
self.events_per_sec = events_per_sec;
self.snapshots.push((self.tick, self.events_per_sec as f64));
self.tick += 1.0;
if self.snapshots.len() > 120 {
self.snapshots.remove(0);
}
}
}
impl Widget for EventsGraphWidget {
fn render(&mut self, f: &mut Frame<'_>, area: Rect) {
self.area = Some(area);
let block = Block::default()
.title(self.title)
.border_type(BorderType::Rounded)
.borders(Borders::ALL)
.border_style(if self.focused {
Style::default().fg(Color::Cyan)
} else {
Style::default().fg(Color::White)
});
let (x_min, x_max) =
if let (Some(first), Some(last)) = (self.snapshots.first(), self.snapshots.last()) {
(first.0, last.0.max(60.0)) } else {
(0.0, 60.0)
};
let mid_x = (x_min + x_max) / 2.0;
let x_labels = vec![
Span::raw(format!("{:.0}s", x_min)),
Span::raw(format!("{:.0}s", mid_x)),
Span::raw(format!("{:.0}s", x_max)),
];
let y_max = self
.snapshots
.iter()
.map(|(_, v)| *v)
.fold(0.0, f64::max)
.max(50.0) .ceil();
let clamped_data: Vec<(f64, f64)> = self
.snapshots
.iter()
.map(|(x, y)| (*x, y.min(y_max)))
.collect();
let y_labels = vec![
Span::raw("0"),
Span::raw(format!("{:.0}", y_max / 2.0)),
Span::raw(format!("{:.0}", y_max)),
];
let dataset = Dataset::default()
.marker(symbols::Marker::Braille)
.style(Style::default().fg(Color::Yellow))
.graph_type(GraphType::Line)
.data(&clamped_data);
let chart = Chart::new(vec![dataset])
.block(block)
.x_axis(
Axis::default()
.title("Time (s)")
.style(Style::default().fg(Color::Gray))
.labels(x_labels)
.bounds([x_min, x_max]),
)
.y_axis(
Axis::default()
.title("Events/sec")
.style(Style::default().fg(Color::Gray))
.labels(y_labels)
.bounds([0.0, y_max]),
);
f.render_widget(chart, area);
}
fn on_key(&mut self, _key: KeyEvent) {
}
fn on_mouse(&mut self, _me: MouseEvent) {}
}