use iced_plot::{
Color, LineStyle, MarkerStyle, PlotUiMessage, PlotWidget, PlotWidgetBuilder, Series, Tick,
TickWeight,
};
use iced::Element;
fn main() -> iced::Result {
iced::application(new, update, view)
.theme(iced::theme::Theme::KanagawaDragon)
.font(include_bytes!("fonts/FiraCodeNerdFont-Regular.ttf"))
.default_font(iced::Font::with_name("FiraCode Nerd Font"))
.run()
}
fn update(widget: &mut PlotWidget, message: PlotUiMessage) {
widget.update(message);
}
fn view(widget: &PlotWidget) -> Element<'_, PlotUiMessage> {
widget.view()
}
fn new() -> PlotWidget {
let mut positions: Vec<[f64; 2]> = Vec::new();
let mut temps: Vec<f64> = Vec::new();
for hour in 0..=24 {
let t = hour as f64;
let temp = 20.0 + 10.0 * (std::f64::consts::PI * (t - 6.0) / 12.0).sin();
positions.push([t * 3600.0, temp]);
temps.push(temp);
}
let (min_temp, max_temp) = temps.iter().fold((f64::MAX, f64::MIN), |acc, t| {
(acc.0.min(*t), acc.1.max(*t))
});
let temp_span = (max_temp - min_temp).max(1e-6);
let colors: Vec<Color> = temps
.iter()
.map(|t| {
let n = ((*t - min_temp) / temp_span) as f32;
let r = 0.2 + 0.8 * n;
let g = 0.3 + 0.2 * (1.0 - n);
let b = 1.0 - 0.8 * n;
Color::from_rgb(r, g, b)
})
.collect();
let series = Series::new(positions, MarkerStyle::circle(5.0), LineStyle::Solid)
.with_label("Temperature")
.with_point_colors(colors)
.with_color(Color::from_rgb(1.0, 0.5, 0.2));
PlotWidgetBuilder::new()
.add_series(series)
.with_x_label("Time of Day\n\n\n")
.with_y_label("Temperature")
.with_x_tick_producer(|min, max| {
let hour_in_seconds = 3600.0;
let tick_interval = 4.0 * hour_in_seconds;
let start = (min / tick_interval).floor() * tick_interval;
let mut ticks = Vec::new();
let mut value = start;
while value <= max {
if value >= min {
ticks.push(Tick {
value,
step_size: tick_interval,
line_type: TickWeight::Major,
});
}
value += tick_interval;
}
ticks
})
.with_x_tick_formatter(|tick| {
let total_seconds = tick.value as i64;
let hours = (total_seconds / 3600) % 24;
let minutes = (total_seconds % 3600) / 60;
format!("{:02}:{:02}", hours, minutes)
})
.with_y_tick_producer(|min, max| {
let tick_interval = 5.0;
let start = (min / tick_interval).floor() * tick_interval;
let mut ticks = Vec::new();
let mut value = start;
while value <= max {
if value >= min {
ticks.push(Tick {
value,
step_size: tick_interval,
line_type: TickWeight::Major,
});
}
value += tick_interval;
}
ticks
})
.with_y_tick_formatter(|tick| format!("{:.0}°C", tick.value))
.with_cursor_provider(|x, y| {
let hours = (x as i64 / 3600) % 24;
let minutes = (x as i64 % 3600) / 60;
format!("Time: {:02}:{:02}\nTemp: {:.1}°C", hours, minutes, y)
})
.with_hover_highlight_provider(|context, point| {
point.color = Color::from_rgb(1.0, 0.5, 0.2);
point.resize_marker(1.5);
let hours = (point.x as i64 / 3600) % 24;
let minutes = (point.x as i64 % 3600) / 60;
Some(format!(
"{}\nTime: {:02}:{:02}\nTemp: {:.1}°C",
context.series_label, hours, minutes, point.y
))
})
.with_pick_highlight_provider(|context, point| {
point.color = Color::from_rgb(1.0, 0.0, 0.0);
point.resize_marker(3.0);
point.mask_padding = None;
let hours = (point.x as i64 / 3600) % 24;
let minutes = (point.x as i64 % 3600) / 60;
Some(format!(
"{}\nTime: {:02}:{:02}\nTemp: {:.1}°C",
context.series_label, hours, minutes, point.y
))
})
.build()
.unwrap()
}