mirror of
https://git.alemi.dev/dashboard.git
synced 2024-11-12 19:29:18 +01:00
feat!: added view offset and reduce, ui tweaks
view reduce averages chunks of X values, view offset shifts the "now" back. Improved panel options UI
This commit is contained in:
parent
e8df50f010
commit
7c6f765455
5 changed files with 121 additions and 34 deletions
|
@ -79,9 +79,16 @@ impl ApplicationState {
|
|||
.expect("Storage Mutex poisoned")
|
||||
.new_panel(
|
||||
panel.name.as_str(),
|
||||
false,
|
||||
panel.view_size,
|
||||
5,
|
||||
0,
|
||||
true,
|
||||
panel.width,
|
||||
panel.height,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
self.panels.read().expect("Panels RwLock poisoned").len() as i32, // todo can this be made more compact and without acquisition?
|
||||
)?; // TODO make values customizable and useful
|
||||
self.panels
|
||||
|
|
|
@ -4,15 +4,20 @@ use eframe::egui::plot::{Value, Values};
|
|||
use eframe::epaint::Color32;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Panel {
|
||||
pub(crate) id: i32,
|
||||
pub name: String,
|
||||
pub view_scroll: bool,
|
||||
pub view_size: i32,
|
||||
pub view_size: u32,
|
||||
pub view_chunks: u32,
|
||||
pub view_offset: u32,
|
||||
pub timeserie: bool,
|
||||
pub(crate) width: i32,
|
||||
pub(crate) height: i32,
|
||||
pub limit: bool,
|
||||
pub reduce: bool,
|
||||
pub shift: bool,
|
||||
}
|
||||
|
||||
impl Default for Panel {
|
||||
|
@ -22,14 +27,19 @@ impl Default for Panel {
|
|||
name: "".to_string(),
|
||||
view_scroll: true,
|
||||
view_size: 300,
|
||||
view_chunks: 5,
|
||||
view_offset: 0,
|
||||
timeserie: true,
|
||||
width: 100,
|
||||
height: 200,
|
||||
limit: false,
|
||||
reduce: false,
|
||||
shift: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Source {
|
||||
pub(crate) id: i32,
|
||||
pub name: String,
|
||||
|
@ -64,19 +74,37 @@ impl Default for Source {
|
|||
}
|
||||
}
|
||||
|
||||
fn avg_value(values: &[Value]) -> Value {
|
||||
let mut x = 0.0;
|
||||
let mut y = 0.0;
|
||||
for v in values {
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
}
|
||||
return Value { x: x / values.len() as f64, y: y / values.len() as f64 };
|
||||
}
|
||||
|
||||
impl Source {
|
||||
pub fn valid(&self) -> bool {
|
||||
let last_fetch = self.last_fetch.read().expect("LastFetch RwLock poisoned");
|
||||
return (Utc::now() - *last_fetch).num_seconds() < self.interval as i64;
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Values {
|
||||
Values::from_values(self.data.read().expect("Values RwLock poisoned").clone())
|
||||
}
|
||||
|
||||
pub fn values_filter(&self, min_x: f64) -> Values {
|
||||
// TODO optimize this with caching!
|
||||
pub fn values(&self, min_x: Option<f64>, max_x: Option<f64>, chunk_size: Option<u32>) -> Values {
|
||||
let mut values = self.data.read().expect("Values RwLock poisoned").clone();
|
||||
values.retain(|x| x.x > min_x);
|
||||
if let Some(min_x) = min_x {
|
||||
values.retain(|x| x.x > min_x);
|
||||
}
|
||||
if let Some(max_x) = max_x {
|
||||
values.retain(|x| x.x < max_x);
|
||||
}
|
||||
if let Some(chunk_size) = chunk_size {
|
||||
if chunk_size > 0 { // TODO make this nested if prettier
|
||||
let iter = values.chunks(chunk_size as usize);
|
||||
values = iter.map(|x| avg_value(x) ).collect();
|
||||
}
|
||||
}
|
||||
Values::from_values(values)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,11 @@ impl SQLiteDataStore {
|
|||
width INT NOT NULL,
|
||||
height INT NOT NULL,
|
||||
limit_view BOOL NOT NULL,
|
||||
position INT NOT NULL
|
||||
position INT NOT NULL,
|
||||
reduce_view BOOL NOT NULL,
|
||||
view_chunks INT NOT NULL,
|
||||
shift_view BOOL NOT NULL,
|
||||
view_offset INT NOT NULL
|
||||
);",
|
||||
[],
|
||||
)?;
|
||||
|
@ -212,6 +216,11 @@ impl SQLiteDataStore {
|
|||
width: row.get(5)?,
|
||||
height: row.get(6)?,
|
||||
limit: row.get(7)?,
|
||||
// position: row.get(8)?,
|
||||
reduce: row.get(9)?,
|
||||
view_chunks: row.get(10)?,
|
||||
shift: row.get(11)?,
|
||||
view_offset: row.get(12)?,
|
||||
})
|
||||
})?;
|
||||
|
||||
|
@ -228,14 +237,21 @@ impl SQLiteDataStore {
|
|||
pub fn new_panel(
|
||||
&self,
|
||||
name: &str,
|
||||
view_size: i32,
|
||||
view_scroll: bool,
|
||||
view_size: u32,
|
||||
view_chunks: u32,
|
||||
view_offset: u32,
|
||||
timeserie: bool,
|
||||
width: i32,
|
||||
height: i32,
|
||||
limit: bool,
|
||||
reduce: bool,
|
||||
shift: bool,
|
||||
position: i32,
|
||||
) -> rusqlite::Result<Panel> {
|
||||
self.conn.execute(
|
||||
"INSERT INTO panels (name, view_scroll, view_size, timeserie, width, height, limit_view, position) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
params![name, true, view_size, true, width, height, false, position]
|
||||
"INSERT INTO panels (name, view_scroll, view_size, timeserie, width, height, limit_view, position, reduce_view, view_chunks, shift_view, view_offset) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
params![name, view_scroll, view_size, timeserie, width, height, limit, position, reduce, view_chunks, shift, view_offset]
|
||||
)?;
|
||||
let mut statement = self.conn.prepare("SELECT * FROM panels WHERE name = ?")?;
|
||||
for panel in statement.query_map(params![name], |row| {
|
||||
|
@ -248,6 +264,11 @@ impl SQLiteDataStore {
|
|||
width: row.get(5)?,
|
||||
height: row.get(6)?,
|
||||
limit: row.get(7)?,
|
||||
// position: row.get(8)?,
|
||||
reduce: row.get(9)?,
|
||||
view_chunks: row.get(10)?,
|
||||
shift: row.get(11)?,
|
||||
view_offset: row.get(12)?,
|
||||
})
|
||||
})? {
|
||||
if let Ok(p) = panel {
|
||||
|
@ -262,16 +283,20 @@ impl SQLiteDataStore {
|
|||
id: i32,
|
||||
name: &str,
|
||||
view_scroll: bool,
|
||||
view_size: i32,
|
||||
view_size: u32,
|
||||
view_chunks: u32,
|
||||
view_offset: u32,
|
||||
timeserie: bool,
|
||||
width: i32,
|
||||
height: i32,
|
||||
limit: bool,
|
||||
reduce: bool,
|
||||
shift: bool,
|
||||
position: i32,
|
||||
) -> rusqlite::Result<usize> {
|
||||
self.conn.execute(
|
||||
"UPDATE panels SET name = ?, view_scroll = ?, view_size = ?, timeserie = ?, width = ?, height = ?, limit_view = ?, position = ? WHERE id = ?",
|
||||
params![name, view_scroll, view_size, timeserie, width, height, limit, position, id],
|
||||
"UPDATE panels SET name = ?, view_scroll = ?, view_size = ?, timeserie = ?, width = ?, height = ?, limit_view = ?, position = ?, reduce_view = ?, view_chunks = ?, shift_view = ?, view_offset = ? WHERE id = ?",
|
||||
params![name, view_scroll, view_size, timeserie, width, height, limit, position, reduce, view_chunks, shift, view_offset, id],
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,15 +21,37 @@ pub fn panel_title_ui(ui: &mut Ui, panel: &mut Panel, extra: bool) {
|
|||
ui.heading(panel.name.as_str());
|
||||
ui.with_layout(Layout::right_to_left(), |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.toggle_value(&mut panel.view_scroll, " • ");
|
||||
ui.toggle_value(&mut panel.view_scroll, "🔒");
|
||||
ui.separator();
|
||||
ui.label("m");
|
||||
ui.add(
|
||||
DragValue::new(&mut panel.view_size)
|
||||
.speed(10)
|
||||
.clamp_range(0..=2147483647i32),
|
||||
);
|
||||
ui.checkbox(&mut panel.limit, "limit");
|
||||
if panel.limit {
|
||||
ui.label("min"); // TODO makes no sense if it's not a timeserie
|
||||
ui.add(
|
||||
DragValue::new(&mut panel.view_size)
|
||||
.speed(10)
|
||||
.clamp_range(0..=2147483647i32),
|
||||
);
|
||||
}
|
||||
ui.toggle_value(&mut panel.limit, "limit");
|
||||
ui.separator();
|
||||
if panel.shift {
|
||||
ui.label("min");
|
||||
ui.add(
|
||||
DragValue::new(&mut panel.view_offset)
|
||||
.speed(10)
|
||||
.clamp_range(0..=2147483647i32),
|
||||
);
|
||||
}
|
||||
ui.toggle_value(&mut panel.shift, "offset");
|
||||
ui.separator();
|
||||
if panel.reduce {
|
||||
ui.label("x");
|
||||
ui.add(
|
||||
DragValue::new(&mut panel.view_chunks)
|
||||
.speed(1)
|
||||
.clamp_range(1..=1000), // TODO allow to average larger spans maybe?
|
||||
);
|
||||
}
|
||||
ui.toggle_value(&mut panel.reduce, "reduce");
|
||||
if extra {
|
||||
ui.separator();
|
||||
ui.checkbox(&mut panel.timeserie, "timeserie");
|
||||
|
@ -52,11 +74,12 @@ pub fn panel_body_ui(ui: &mut Ui, panel: &mut Panel, sources: &Vec<Source>) {
|
|||
}
|
||||
|
||||
if panel.view_scroll {
|
||||
p = p.include_x(Utc::now().timestamp() as f64);
|
||||
let _now = (Utc::now().timestamp() as f64) - (60.0 * panel.view_offset as f64);
|
||||
p = p.include_x(_now);
|
||||
if panel.limit {
|
||||
p = p
|
||||
.include_x((Utc::now().timestamp() + (panel.view_size as i64 * 3)) as f64)
|
||||
.include_x((Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64); // ??? TODO
|
||||
.include_x(_now + (panel.view_size as f64 * 3.0))
|
||||
.include_x(_now - (panel.view_size as f64 * 60.0)); // ??? TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,16 +129,16 @@ pub fn panel_body_ui(ui: &mut Ui, panel: &mut Panel, sources: &Vec<Source>) {
|
|||
}
|
||||
|
||||
p.show(ui, |plot_ui| {
|
||||
for source in &*sources {
|
||||
for source in sources {
|
||||
if source.panel_id == panel.id {
|
||||
let line = if panel.limit {
|
||||
Line::new(source.values_filter(
|
||||
(Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64,
|
||||
))
|
||||
.name(source.name.as_str())
|
||||
} else {
|
||||
Line::new(source.values()).name(source.name.as_str())
|
||||
};
|
||||
let _now = Utc::now().timestamp() as f64;
|
||||
let _off = (panel.view_offset as f64) * 60.0; // TODO multiplying x60 makes sense only for timeseries
|
||||
let _size = (panel.view_size as f64) * 60.0; // TODO multiplying x60 makes sense only for timeseries
|
||||
let min_x = if panel.limit { Some(_now - _size - _off) } else { None };
|
||||
let max_x = if panel.shift { Some(_now - _off) } else { None };
|
||||
let chunk_size = if panel.reduce { Some(panel.view_chunks) } else { None };
|
||||
// let chunks = None;
|
||||
let line = Line::new(source.values(min_x, max_x, chunk_size)).name(source.name.as_str());
|
||||
plot_ui.line(line.color(source.color));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,14 @@ pub fn native_save(state: Arc<ApplicationState>) {
|
|||
panel.name.as_str(),
|
||||
panel.view_scroll,
|
||||
panel.view_size,
|
||||
panel.view_chunks,
|
||||
panel.view_offset,
|
||||
panel.timeserie,
|
||||
panel.width,
|
||||
panel.height,
|
||||
panel.limit,
|
||||
panel.reduce,
|
||||
panel.shift,
|
||||
index as i32,
|
||||
) {
|
||||
warn!(target: "native-save", "Could not update panel #{} : {:?}", panel.id, e);
|
||||
|
|
Loading…
Reference in a new issue