notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

sparkline.rs (2270B)


      1 use egui::{Color32, Pos2, Response, Sense, Stroke, Ui, Vec2};
      2 
      3 #[derive(Clone, Copy)]
      4 pub struct SparkStyle {
      5     pub stroke: Stroke,
      6     //pub fill_alpha: u8,
      7     //pub rounding: f32,
      8 }
      9 
     10 impl Default for SparkStyle {
     11     fn default() -> Self {
     12         Self {
     13             stroke: Stroke::new(1.5, Color32::WHITE),
     14             //fill_alpha: 40,
     15             //rounding: 3.0,
     16         }
     17     }
     18 }
     19 
     20 /// values are samples over time (left=oldest, right=newest)
     21 pub fn sparkline(
     22     ui: &mut Ui,
     23     size: Vec2,
     24     values: &[f32],
     25     color: Color32,
     26     style: SparkStyle,
     27 ) -> Response {
     28     let (rect, resp) = ui.allocate_exact_size(size, Sense::hover());
     29     let painter = ui.painter_at(rect);
     30 
     31     // background
     32     //painter.rect_filled(rect, style.rounding, ui.visuals().widgets.inactive.bg_fill);
     33 
     34     if values.len() < 2 {
     35         return resp;
     36     }
     37 
     38     let mut min_v = f32::INFINITY;
     39     let mut max_v = f32::NEG_INFINITY;
     40     for &v in values {
     41         let v = v.max(0.0);
     42         min_v = min_v.min(v);
     43         max_v = max_v.max(v);
     44     }
     45     // avoid div by zero, also allow flat lines
     46     let span = (max_v - min_v).max(1.0);
     47 
     48     let n = values.len();
     49     let dx = rect.width() / (n.saturating_sub(1) as f32).max(1.0);
     50 
     51     let mut pts: Vec<Pos2> = Vec::with_capacity(n);
     52     for (i, &v) in values.iter().enumerate() {
     53         let t = (v.max(0.0) - min_v) / span; // 0..1
     54         let x = rect.left() + (i as f32) * dx;
     55         let y = rect.bottom() - t * rect.height();
     56         pts.push(Pos2::new(x, y));
     57     }
     58 
     59     // fill under curve
     60     /*
     61     let mut fill_pts = Vec::with_capacity(pts.len() + 2);
     62     fill_pts.extend_from_slice(&pts);
     63     fill_pts.push(Pos2::new(rect.right(), rect.bottom()));
     64     fill_pts.push(Pos2::new(rect.left(), rect.bottom()));
     65 
     66     let mut fill_color = color;
     67     fill_color = Color32::from_rgba_premultiplied(
     68         fill_color.r(),
     69         fill_color.g(),
     70         fill_color.b(),
     71         style.fill_alpha,
     72     );
     73 
     74     painter.add(egui::Shape::Path(egui::epaint::PathShape {
     75         points: fill_pts,
     76         closed: true,
     77         fill: fill_color,
     78         stroke: Stroke::NONE.into(),
     79     }));
     80     */
     81 
     82     // line
     83     painter.add(egui::Shape::line(
     84         pts,
     85         Stroke::new(style.stroke.width, color),
     86     ));
     87 
     88     resp
     89 }