2021-02-14 20:39:04 +00:00
|
|
|
use egui::*;
|
2021-06-07 20:36:13 +00:00
|
|
|
use plot::{Corner, Legend, Line, MarkerShape, Plot, Points, Value, Values};
|
2021-02-14 20:39:04 +00:00
|
|
|
use std::f64::consts::TAU;
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
2021-05-27 16:40:20 +00:00
|
|
|
struct LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
animate: bool,
|
|
|
|
time: f64,
|
2021-04-24 12:26:54 +00:00
|
|
|
circle_radius: f64,
|
2021-02-14 20:39:04 +00:00
|
|
|
circle_center: Pos2,
|
|
|
|
square: bool,
|
|
|
|
proportional: bool,
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl Default for LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
animate: true,
|
|
|
|
time: 0.0,
|
2021-04-24 12:26:54 +00:00
|
|
|
circle_radius: 1.5,
|
2021-02-14 20:39:04 +00:00
|
|
|
circle_center: Pos2::new(0.0, 0.0),
|
|
|
|
square: false,
|
|
|
|
proportional: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl LineDemo {
|
2021-02-14 20:39:04 +00:00
|
|
|
fn options_ui(&mut self, ui: &mut Ui) {
|
|
|
|
let Self {
|
|
|
|
animate,
|
|
|
|
time: _,
|
|
|
|
circle_radius,
|
|
|
|
circle_center,
|
|
|
|
square,
|
|
|
|
proportional,
|
2021-05-27 16:40:20 +00:00
|
|
|
..
|
2021-02-14 20:39:04 +00:00
|
|
|
} = self;
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.group(|ui| {
|
|
|
|
ui.vertical(|ui| {
|
|
|
|
ui.label("Circle:");
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(circle_radius)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(0.1)
|
|
|
|
.clamp_range(0.0..=f32::INFINITY)
|
|
|
|
.prefix("r: "),
|
2021-02-14 20:39:04 +00:00
|
|
|
);
|
2021-03-07 18:51:07 +00:00
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(&mut circle_center.x)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(0.1)
|
|
|
|
.prefix("x: "),
|
|
|
|
);
|
|
|
|
ui.add(
|
2021-03-27 15:09:09 +00:00
|
|
|
egui::DragValue::new(&mut circle_center.y)
|
2021-03-07 18:51:07 +00:00
|
|
|
.speed(1.0)
|
|
|
|
.prefix("y: "),
|
|
|
|
);
|
|
|
|
});
|
2021-02-14 20:39:04 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.vertical(|ui| {
|
|
|
|
ui.style_mut().wrap = Some(false);
|
|
|
|
ui.checkbox(animate, "animate");
|
|
|
|
ui.checkbox(square, "square view");
|
|
|
|
ui.checkbox(proportional, "proportional data axes");
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn circle(&self) -> Line {
|
2021-02-14 20:39:04 +00:00
|
|
|
let n = 512;
|
|
|
|
let circle = (0..=n).map(|i| {
|
|
|
|
let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU);
|
2021-04-24 12:26:54 +00:00
|
|
|
let r = self.circle_radius;
|
2021-02-14 20:39:04 +00:00
|
|
|
Value::new(
|
|
|
|
r * t.cos() + self.circle_center.x as f64,
|
|
|
|
r * t.sin() + self.circle_center.y as f64,
|
|
|
|
)
|
|
|
|
});
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_values_iter(circle))
|
2021-02-14 20:39:04 +00:00
|
|
|
.color(Color32::from_rgb(100, 200, 100))
|
|
|
|
.name("circle")
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn sin(&self) -> Line {
|
2021-04-24 12:26:54 +00:00
|
|
|
let time = self.time;
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_explicit_callback(
|
2021-04-24 12:26:54 +00:00
|
|
|
move |x| 0.5 * (2.0 * x).sin() * time.sin(),
|
|
|
|
f64::NEG_INFINITY..=f64::INFINITY,
|
|
|
|
512,
|
2021-05-27 16:40:20 +00:00
|
|
|
))
|
2021-04-24 12:26:54 +00:00
|
|
|
.color(Color32::from_rgb(200, 100, 100))
|
2021-05-10 15:06:50 +00:00
|
|
|
.name("wave")
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
fn thingy(&self) -> Line {
|
2021-04-24 12:26:54 +00:00
|
|
|
let time = self.time;
|
2021-05-27 16:40:20 +00:00
|
|
|
Line::new(Values::from_parametric_callback(
|
2021-04-24 12:26:54 +00:00
|
|
|
move |t| ((2.0 * t + time).sin(), (3.0 * t).sin()),
|
|
|
|
0.0..=TAU,
|
2021-05-27 16:40:20 +00:00
|
|
|
256,
|
|
|
|
))
|
2021-04-24 12:26:54 +00:00
|
|
|
.color(Color32::from_rgb(100, 150, 250))
|
|
|
|
.name("x = sin(2t), y = sin(3t)")
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:40:20 +00:00
|
|
|
impl Widget for &mut LineDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
2021-02-14 20:39:04 +00:00
|
|
|
self.options_ui(ui);
|
|
|
|
if self.animate {
|
|
|
|
ui.ctx().request_repaint();
|
|
|
|
self.time += ui.input().unstable_dt.at_most(1.0 / 30.0) as f64;
|
|
|
|
};
|
2021-05-27 16:40:20 +00:00
|
|
|
let mut plot = Plot::new("Lines Demo")
|
|
|
|
.line(self.circle())
|
|
|
|
.line(self.sin())
|
|
|
|
.line(self.thingy())
|
2021-06-07 20:36:13 +00:00
|
|
|
.legend(Legend::default());
|
2021-02-14 20:39:04 +00:00
|
|
|
if self.square {
|
|
|
|
plot = plot.view_aspect(1.0);
|
|
|
|
}
|
|
|
|
if self.proportional {
|
|
|
|
plot = plot.data_aspect(1.0);
|
|
|
|
}
|
2021-05-27 16:40:20 +00:00
|
|
|
ui.add(plot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct MarkerDemo {
|
|
|
|
fill_markers: bool,
|
|
|
|
marker_radius: f32,
|
|
|
|
custom_marker_color: bool,
|
|
|
|
marker_color: Color32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for MarkerDemo {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
fill_markers: true,
|
|
|
|
marker_radius: 5.0,
|
|
|
|
custom_marker_color: false,
|
|
|
|
marker_color: Color32::GRAY,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MarkerDemo {
|
|
|
|
fn markers(&self) -> Vec<Points> {
|
|
|
|
MarkerShape::all()
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, marker)| {
|
|
|
|
let y_offset = i as f32 * 0.5 + 1.0;
|
|
|
|
let mut points = Points::new(Values::from_values(vec![
|
|
|
|
Value::new(1.0, 0.0 + y_offset),
|
|
|
|
Value::new(2.0, 0.5 + y_offset),
|
|
|
|
Value::new(3.0, 0.0 + y_offset),
|
|
|
|
Value::new(4.0, 0.5 + y_offset),
|
|
|
|
Value::new(5.0, 0.0 + y_offset),
|
|
|
|
Value::new(6.0, 0.5 + y_offset),
|
|
|
|
]))
|
|
|
|
.name(format!("{:?}", marker))
|
|
|
|
.filled(self.fill_markers)
|
|
|
|
.radius(self.marker_radius)
|
|
|
|
.shape(marker);
|
|
|
|
|
|
|
|
if self.custom_marker_color {
|
|
|
|
points = points.color(self.marker_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
points
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widget for &mut MarkerDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.checkbox(&mut self.fill_markers, "fill markers");
|
|
|
|
ui.add(
|
|
|
|
egui::DragValue::new(&mut self.marker_radius)
|
|
|
|
.speed(0.1)
|
|
|
|
.clamp_range(0.0..=f32::INFINITY)
|
|
|
|
.prefix("marker radius: "),
|
|
|
|
);
|
|
|
|
ui.checkbox(&mut self.custom_marker_color, "custom marker color");
|
|
|
|
if self.custom_marker_color {
|
|
|
|
ui.color_edit_button_srgba(&mut self.marker_color);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-06-07 20:36:13 +00:00
|
|
|
let mut markers_plot = Plot::new("Markers Demo")
|
|
|
|
.data_aspect(1.0)
|
|
|
|
.legend(Legend::default());
|
2021-05-27 16:40:20 +00:00
|
|
|
for marker in self.markers() {
|
|
|
|
markers_plot = markers_plot.points(marker);
|
|
|
|
}
|
|
|
|
ui.add(markers_plot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 20:36:13 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct LegendDemo {
|
|
|
|
config: Legend,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for LegendDemo {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
config: Legend::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LegendDemo {
|
|
|
|
fn line_with_slope(slope: f64) -> Line {
|
|
|
|
Line::new(Values::from_explicit_callback(
|
|
|
|
move |x| slope * x,
|
|
|
|
f64::NEG_INFINITY..=f64::INFINITY,
|
|
|
|
100,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
fn sin() -> Line {
|
|
|
|
Line::new(Values::from_explicit_callback(
|
|
|
|
move |x| x.sin(),
|
|
|
|
f64::NEG_INFINITY..=f64::INFINITY,
|
|
|
|
100,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
fn cos() -> Line {
|
|
|
|
Line::new(Values::from_explicit_callback(
|
|
|
|
move |x| x.cos(),
|
|
|
|
f64::NEG_INFINITY..=f64::INFINITY,
|
|
|
|
100,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Widget for &mut LegendDemo {
|
|
|
|
fn ui(self, ui: &mut Ui) -> Response {
|
|
|
|
let LegendDemo { config } = self;
|
|
|
|
|
|
|
|
ui.label("Text Style:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
TextStyle::all().for_each(|style| {
|
|
|
|
ui.selectable_value(&mut config.text_style, style, format!("{:?}", style));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
ui.label("Position:");
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
Corner::all().for_each(|position| {
|
|
|
|
ui.selectable_value(&mut config.position, position, format!("{:?}", position));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
let legend_plot = Plot::new("Legend Demo")
|
|
|
|
.line(LegendDemo::line_with_slope(0.5).name("lines"))
|
|
|
|
.line(LegendDemo::line_with_slope(1.0).name("lines"))
|
|
|
|
.line(LegendDemo::line_with_slope(2.0).name("lines"))
|
|
|
|
.line(LegendDemo::sin().name("sin(x)"))
|
|
|
|
.line(LegendDemo::cos().name("cos(x)"))
|
|
|
|
.legend(*config)
|
|
|
|
.data_aspect(1.0);
|
|
|
|
ui.add(legend_plot)
|
|
|
|
}
|
|
|
|
}
|
2021-05-27 16:40:20 +00:00
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
enum Panel {
|
|
|
|
Lines,
|
|
|
|
Markers,
|
2021-06-07 20:36:13 +00:00
|
|
|
Legend,
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Panel {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Lines
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Default)]
|
|
|
|
pub struct PlotDemo {
|
|
|
|
line_demo: LineDemo,
|
|
|
|
marker_demo: MarkerDemo,
|
2021-06-07 20:36:13 +00:00
|
|
|
legend_demo: LegendDemo,
|
2021-05-27 16:40:20 +00:00
|
|
|
open_panel: Panel,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::Demo for PlotDemo {
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
"🗠 Plot"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn show(&mut self, ctx: &CtxRef, open: &mut bool) {
|
|
|
|
use super::View;
|
|
|
|
Window::new(self.name())
|
|
|
|
.open(open)
|
|
|
|
.default_size(vec2(400.0, 400.0))
|
|
|
|
.scroll(false)
|
|
|
|
.show(ctx, |ui| self.ui(ui));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::View for PlotDemo {
|
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
|
|
|
ui.vertical_centered(|ui| {
|
|
|
|
egui::reset_button(ui, self);
|
|
|
|
ui.add(crate::__egui_github_link_file!());
|
|
|
|
ui.label("Pan by dragging, or scroll (+ shift = horizontal).");
|
|
|
|
if cfg!(target_arch = "wasm32") {
|
|
|
|
ui.label("Zoom with ctrl / ⌘ + mouse wheel, or with pinch gesture.");
|
|
|
|
} else if cfg!(target_os = "macos") {
|
|
|
|
ui.label("Zoom with ctrl / ⌘ + scroll.");
|
|
|
|
} else {
|
|
|
|
ui.label("Zoom with ctrl + scroll.");
|
|
|
|
}
|
|
|
|
ui.label("Reset view with double-click.");
|
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Lines, "Lines");
|
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Markers, "Markers");
|
2021-06-07 20:36:13 +00:00
|
|
|
ui.selectable_value(&mut self.open_panel, Panel::Legend, "Legend");
|
2021-05-27 16:40:20 +00:00
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
match self.open_panel {
|
|
|
|
Panel::Lines => {
|
|
|
|
ui.add(&mut self.line_demo);
|
|
|
|
}
|
|
|
|
Panel::Markers => {
|
|
|
|
ui.add(&mut self.marker_demo);
|
|
|
|
}
|
2021-06-07 20:36:13 +00:00
|
|
|
Panel::Legend => {
|
|
|
|
ui.add(&mut self.legend_demo);
|
|
|
|
}
|
2021-05-27 16:40:20 +00:00
|
|
|
}
|
2021-02-14 20:39:04 +00:00
|
|
|
}
|
|
|
|
}
|