use std::collections::VecDeque;
pub fn next_power_of_2_scaled(value: f64) -> f64 {
if value <= 2048.0 {
return 2048.0;
}
let mut result = 2048.0;
while result < value {
result *= 2.0;
}
result
}
pub fn render_graph(
history: &VecDeque<f64>,
width: usize,
height: usize,
max_value: f64,
unicode: bool,
) -> Vec<String> {
if width == 0 || height == 0 {
return vec![];
}
let mut values: Vec<f64> = history
.iter()
.take(width)
.copied()
.map(|v| v.max(0.0))
.collect();
values.resize(width, 0.0);
let max_val = if max_value <= 0.0 {
let peak = values.iter().cloned().fold(0.0_f64, f64::max);
next_power_of_2_scaled(peak)
} else {
max_value
};
let max_val = if max_val <= 0.0 { 2048.0 } else { max_val };
let (ch_full, ch_high, ch_low, ch_dot) = if unicode {
('█', '▓', '░', '·')
} else {
('#', '|', '.', '.')
};
let mut lines = Vec::with_capacity(height);
for row in 0..height {
let mut chars = String::with_capacity(width);
for col in 0..width {
let val_idx = width - 1 - col;
let value = values[val_idx];
let lower_limit = max_val * (height - row - 1) as f64 / height as f64;
let traffic_per_line = max_val / height as f64;
if value <= lower_limit {
chars.push(' ');
} else {
let rest = value - lower_limit;
if rest >= traffic_per_line {
chars.push(ch_full);
} else if rest >= traffic_per_line * 0.7 {
chars.push(ch_high);
} else if rest >= traffic_per_line * 0.3 {
chars.push(ch_low);
} else {
chars.push(ch_dot);
}
}
}
lines.push(chars);
}
lines
}
pub fn get_graph_scale_label_unit(max_value: f64, unit: crate::Unit) -> String {
use crate::stats::format_speed_unit;
format!("100% @ {}", format_speed_unit(max_value, unit))
}