#[allow(dead_code)] mod util; use crate::util::{ event::{Event, Events}, SinSignal, }; use std::{error::Error, io}; use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen}; use tui::{ backend::TermionBackend, layout::{Constraint, Direction, Layout}, style::{Color, Modifier, Style}, symbols, text::Span, widgets::{Axis, Block, Borders, Chart, Dataset, GraphType}, Terminal, }; const DATA: [(f64, f64); 5] = [(0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (4.0, 4.0)]; const DATA2: [(f64, f64); 7] = [ (0.0, 0.0), (10.0, 1.0), (20.0, 0.5), (30.0, 1.5), (40.0, 1.0), (50.0, 2.5), (60.0, 3.0), ]; struct App { signal1: SinSignal, data1: Vec<(f64, f64)>, signal2: SinSignal, data2: Vec<(f64, f64)>, window: [f64; 2], } impl App { fn new() -> App { let mut signal1 = SinSignal::new(0.2, 3.0, 18.0); let mut signal2 = SinSignal::new(0.1, 2.0, 10.0); let data1 = signal1.by_ref().take(200).collect::>(); let data2 = signal2.by_ref().take(200).collect::>(); App { signal1, data1, signal2, data2, window: [0.0, 20.0], } } fn update(&mut self) { for _ in 0..5 { self.data1.remove(0); } self.data1.extend(self.signal1.by_ref().take(5)); for _ in 0..10 { self.data2.remove(0); } self.data2.extend(self.signal2.by_ref().take(10)); self.window[0] += 1.0; self.window[1] += 1.0; } } fn main() -> Result<(), Box> { // Terminal initialization let stdout = io::stdout().into_raw_mode()?; let stdout = MouseTerminal::from(stdout); let stdout = AlternateScreen::from(stdout); let backend = TermionBackend::new(stdout); let mut terminal = Terminal::new(backend)?; let events = Events::new(); // App let mut app = App::new(); loop { terminal.draw(|f| { let size = f.size(); let chunks = Layout::default() .direction(Direction::Vertical) .constraints( [ Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), ] .as_ref(), ) .split(size); let x_labels = vec![ Span::styled( format!("{}", app.window[0]), Style::default().add_modifier(Modifier::BOLD), ), Span::raw(format!("{}", (app.window[0] + app.window[1]) / 2.0)), Span::styled( format!("{}", app.window[1]), Style::default().add_modifier(Modifier::BOLD), ), ]; let datasets = vec![ Dataset::default() .name("data2") .marker(symbols::Marker::Dot) .style(Style::default().fg(Color::Cyan)) .data(&app.data1), Dataset::default() .name("data3") .marker(symbols::Marker::Braille) .style(Style::default().fg(Color::Yellow)) .data(&app.data2), ]; let chart = Chart::new(datasets) .block( Block::default() .title(Span::styled( "Chart 1", Style::default() .fg(Color::Cyan) .add_modifier(Modifier::BOLD), )) .borders(Borders::ALL), ) .x_axis( Axis::default() .title("X Axis") .style(Style::default().fg(Color::Gray)) .labels(x_labels) .bounds(app.window), ) .y_axis( Axis::default() .title("Y Axis") .style(Style::default().fg(Color::Gray)) .labels(vec![ Span::styled("-20", Style::default().add_modifier(Modifier::BOLD)), Span::raw("0"), Span::styled("20", Style::default().add_modifier(Modifier::BOLD)), ]) .bounds([-20.0, 20.0]), ); f.render_widget(chart, chunks[0]); let datasets = vec![Dataset::default() .name("data") .marker(symbols::Marker::Braille) .style(Style::default().fg(Color::Yellow)) .graph_type(GraphType::Line) .data(&DATA)]; let chart = Chart::new(datasets) .block( Block::default() .title(Span::styled( "Chart 2", Style::default() .fg(Color::Cyan) .add_modifier(Modifier::BOLD), )) .borders(Borders::ALL), ) .x_axis( Axis::default() .title("X Axis") .style(Style::default().fg(Color::Gray)) .bounds([0.0, 5.0]) .labels(vec![ Span::styled("0", Style::default().add_modifier(Modifier::BOLD)), Span::raw("2.5"), Span::styled("5.0", Style::default().add_modifier(Modifier::BOLD)), ]), ) .y_axis( Axis::default() .title("Y Axis") .style(Style::default().fg(Color::Gray)) .bounds([0.0, 5.0]) .labels(vec![ Span::styled("0", Style::default().add_modifier(Modifier::BOLD)), Span::raw("2.5"), Span::styled("5.0", Style::default().add_modifier(Modifier::BOLD)), ]), ); f.render_widget(chart, chunks[1]); let datasets = vec![Dataset::default() .name("data") .marker(symbols::Marker::Braille) .style(Style::default().fg(Color::Yellow)) .graph_type(GraphType::Line) .data(&DATA2)]; let chart = Chart::new(datasets) .block( Block::default() .title(Span::styled( "Chart 3", Style::default() .fg(Color::Cyan) .add_modifier(Modifier::BOLD), )) .borders(Borders::ALL), ) .x_axis( Axis::default() .title("X Axis") .style(Style::default().fg(Color::Gray)) .bounds([0.0, 50.0]) .labels(vec![ Span::styled("0", Style::default().add_modifier(Modifier::BOLD)), Span::raw("25"), Span::styled("50", Style::default().add_modifier(Modifier::BOLD)), ]), ) .y_axis( Axis::default() .title("Y Axis") .style(Style::default().fg(Color::Gray)) .bounds([0.0, 5.0]) .labels(vec![ Span::styled("0", Style::default().add_modifier(Modifier::BOLD)), Span::raw("2.5"), Span::styled("5", Style::default().add_modifier(Modifier::BOLD)), ]), ); f.render_widget(chart, chunks[2]); })?; match events.next()? { Event::Input(input) => { if input == Key::Char('q') { break; } } Event::Tick => { app.update(); } } } Ok(()) }