blob: 9e2a916c439bd8f0d199cf0197843a7e9e30a4a9 [file] [log] [blame]
use std::f64::consts::PI;
use avm_stats::Sample;
use egui::RichText;
use egui_plot::{Plot, PlotPoint, PlotPoints, PlotResponse, Polygon, Text};
pub struct PiePlot {
pub num_vertices: usize,
pub decimal_precision: usize,
}
impl Default for PiePlot {
fn default() -> Self {
Self {
num_vertices: 360,
decimal_precision: 2,
}
}
}
impl PiePlot {
pub fn show(&self, ui: &mut egui::Ui, data: &[Sample]) -> PlotResponse<()> {
let total: f64 = data.iter().map(|sample| sample.value).sum();
let mut cumulative_sum = 0.0;
Plot::new("pie_plot")
.show_background(false)
.show_axes([false; 2])
.clamp_grid(true)
.show_grid(false)
.allow_boxed_zoom(false)
.allow_drag(false)
.allow_zoom(false)
.allow_scroll(false)
.data_aspect(1.0)
.show_x(false)
.show_y(false)
.include_x(-1.1)
.include_x(1.1)
.include_y(-1.1)
.include_y(1.1)
.show(ui, |plot_ui| {
for Sample { name, value } in data.iter() {
let fraction = value / total;
let num_vertices = (self.num_vertices as f64 * fraction).ceil() as usize;
let start_angle = 2.0 * PI * cumulative_sum;
let end_angle = 2.0 * PI * (cumulative_sum + fraction);
cumulative_sum += fraction;
let mut points = vec![];
if data.len() > 1 {
points.push([0.0, 0.0]);
}
let angle_step = (end_angle - start_angle) / num_vertices as f64;
points.extend((0..=num_vertices).map(|i| {
let angle = start_angle + angle_step * i as f64;
[angle.sin(), angle.cos()]
}));
let center_angle = start_angle + (end_angle - start_angle) / 2.0;
let center_x = 0.75 * center_angle.sin();
let center_y = 0.75 * center_angle.cos();
let hovered = plot_ui
.pointer_coordinate()
.map(|pointer| {
let radius = pointer.y.hypot(pointer.x);
let mut theta = pointer.x.atan2(pointer.y);
if theta < 0.0 {
theta += 2.0 * PI;
}
radius < 1.0 && start_angle < theta && theta < end_angle
})
.unwrap_or_default();
plot_ui.polygon(Polygon::new(PlotPoints::new(points)).name(name).highlight(hovered));
let label = format!("{} - {:.2}%", name, 100.0 * value / total);
plot_ui.text(Text::new(PlotPoint::new(center_x, center_y), label));
if hovered {
let pointer = plot_ui.pointer_coordinate().unwrap();
let label = format!(
"{} - {:.2}% ({:.prec$}/{:.prec$})",
name,
100.0 * fraction,
value,
total,
prec = self.decimal_precision
);
plot_ui.text(Text::new(pointer, RichText::new(label).heading()).name(name));
}
}
})
}
}