display basic labels on trip stats

This commit is contained in:
Dustin Carlino 2019-10-01 19:28:03 -07:00
parent 393eaff249
commit 5f9cf2accd
3 changed files with 55 additions and 8 deletions

View File

@ -462,3 +462,23 @@ impl<'a> Prerender<'a> {
} }
} }
} }
pub struct MultiText {
list: Vec<(Text, ScreenPt)>,
}
impl MultiText {
pub fn new() -> MultiText {
MultiText { list: Vec::new() }
}
pub fn add(&mut self, txt: Text, pt: ScreenPt) {
self.list.push((txt, pt));
}
pub fn draw(&self, g: &mut GfxCtx) {
for (txt, pt) in &self.list {
g.draw_text_at_screenspace_topleft(txt, *pt);
}
}
}

View File

@ -12,7 +12,7 @@ pub mod world;
pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment, BOTTOM_LEFT, CENTERED}; pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment, BOTTOM_LEFT, CENTERED};
pub use crate::color::Color; pub use crate::color::Color;
pub use crate::drawing::{Drawable, GeomBatch, GfxCtx, Prerender}; pub use crate::drawing::{Drawable, GeomBatch, GfxCtx, MultiText, Prerender};
pub use crate::event::{hotkey, lctrl, Event, Key, MultiKey}; pub use crate::event::{hotkey, lctrl, Event, Key, MultiKey};
pub use crate::event_ctx::EventCtx; pub use crate::event_ctx::EventCtx;
pub use crate::input::UserInput; pub use crate::input::UserInput;

View File

@ -1,7 +1,9 @@
use crate::common::ColorLegend; use crate::common::ColorLegend;
use crate::game::{State, Transition}; use crate::game::{State, Transition};
use crate::ui::UI; use crate::ui::UI;
use ezgui::{hotkey, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, ModalMenu, Text}; use ezgui::{
ScreenPt, hotkey, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, ModalMenu, MultiText, Text,
};
use geom::{Distance, Duration, PolyLine, Polygon, Pt2D}; use geom::{Distance, Duration, PolyLine, Polygon, Pt2D};
use sim::TripMode; use sim::TripMode;
@ -77,6 +79,7 @@ pub struct ShowStats {
menu: ModalMenu, menu: ModalMenu,
draw: Drawable, draw: Drawable,
legend: ColorLegend, legend: ColorLegend,
labels: MultiText,
} }
impl State for ShowStats { impl State for ShowStats {
@ -95,12 +98,14 @@ impl State for ShowStats {
g.fork_screenspace(); g.fork_screenspace();
g.redraw(&self.draw); g.redraw(&self.draw);
g.unfork(); g.unfork();
self.labels.draw(g);
} }
} }
impl ShowStats { impl ShowStats {
pub fn new(stats: &TripStats, ui: &UI, ctx: &mut EventCtx) -> ShowStats { pub fn new(stats: &TripStats, ui: &UI, ctx: &mut EventCtx) -> ShowStats {
let mut batch = GeomBatch::new(); let mut batch = GeomBatch::new();
let mut labels = MultiText::new();
let x1 = 0.2 * ctx.canvas.window_width; let x1 = 0.2 * ctx.canvas.window_width;
let x2 = 0.8 * ctx.canvas.window_width; let x2 = 0.8 * ctx.canvas.window_width;
@ -118,25 +123,29 @@ impl ShowStats {
let lines: Vec<(&str, Color, Box<dyn Fn(&StateAtTime) -> usize>)> = vec![ let lines: Vec<(&str, Color, Box<dyn Fn(&StateAtTime) -> usize>)> = vec![
( (
"walking", "walking",
ui.cs.get("unzoomed pedestrian").alpha(1.0), ui.cs.get("unzoomed pedestrian"),
Box::new(|s| s.finished_walk_trips), Box::new(|s| s.finished_walk_trips),
), ),
( (
"biking", "biking",
ui.cs.get("unzoomed bike").alpha(1.0), ui.cs.get("unzoomed bike"),
Box::new(|s| s.finished_bike_trips), Box::new(|s| s.finished_bike_trips),
), ),
( (
"transit", "transit",
ui.cs.get("unzoomed bus").alpha(1.0), ui.cs.get("unzoomed bus"),
Box::new(|s| s.finished_transit_trips), Box::new(|s| s.finished_transit_trips),
), ),
( (
"driving", "driving",
ui.cs.get("unzoomed car").alpha(1.0), ui.cs.get("unzoomed car"),
Box::new(|s| s.finished_drive_trips), Box::new(|s| s.finished_drive_trips),
), ),
("aborted", Color::PURPLE, Box::new(|s| s.aborted_trips)), (
"aborted",
Color::PURPLE.alpha(0.5),
Box::new(|s| s.aborted_trips),
),
]; ];
let legend = ColorLegend::new( let legend = ColorLegend::new(
"finished trips", "finished trips",
@ -145,11 +154,28 @@ impl ShowStats {
.map(|(name, color, _)| (*name, *color)) .map(|(name, color, _)| (*name, *color))
.collect(), .collect(),
); );
let max_y = stats.samples.iter().map(|s|
lines.iter().map(|(_, _, getter)| getter(s)).max().unwrap()
).max().unwrap();
// Y-axis labels
for i in 0..=5 {
let percent = (i as f64) / 5.0;
labels.add(Text::from(Line(((percent * (max_y as f64)) as usize).to_string())), ScreenPt::new(x1, y2 - percent * (y2 - y1)));
}
// X-axis labels (currently nonlinear!)
{
let num_pts = stats.samples.len().min(5);
for i in 0..num_pts {
let percent_x = (i as f64) / ((num_pts - 1) as f64);
let t = stats.samples[(percent_x * ((stats.samples.len() - 1) as f64)) as usize].time;
labels.add(Text::from(Line(t.to_string())), ScreenPt::new(x1 + percent_x * (x2 - x1), y2));
}
}
for (_, color, getter) in lines { for (_, color, getter) in lines {
if stats.samples.is_empty() { if stats.samples.is_empty() {
continue; continue;
} }
let max_y = stats.samples.iter().map(&getter).max().unwrap();
let mut pts = Vec::new(); let mut pts = Vec::new();
if max_y == 0 { if max_y == 0 {
pts.push(Pt2D::new(x1, y2)); pts.push(Pt2D::new(x1, y2));
@ -184,6 +210,7 @@ impl ShowStats {
menu: ModalMenu::new("Trip Stats", vec![vec![(hotkey(Key::Escape), "quit")]], ctx) menu: ModalMenu::new("Trip Stats", vec![vec![(hotkey(Key::Escape), "quit")]], ctx)
.set_prompt(ctx, txt), .set_prompt(ctx, txt),
draw: ctx.prerender.upload(batch), draw: ctx.prerender.upload(batch),
labels,
legend, legend,
} }
} }