mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-02 19:35:25 +03:00
Implement Yuwen's interactive signal demand UI, fixing #277
This commit is contained in:
parent
c6a2ae8ded
commit
b75867f0c2
@ -61,16 +61,23 @@ impl WidgetImpl for JustDraw {
|
|||||||
pub struct DrawWithTooltips {
|
pub struct DrawWithTooltips {
|
||||||
draw: Drawable,
|
draw: Drawable,
|
||||||
tooltips: Vec<(Polygon, Text)>,
|
tooltips: Vec<(Polygon, Text)>,
|
||||||
|
hover: Box<dyn Fn(&Polygon) -> GeomBatch>,
|
||||||
|
|
||||||
top_left: ScreenPt,
|
top_left: ScreenPt,
|
||||||
dims: ScreenDims,
|
dims: ScreenDims,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawWithTooltips {
|
impl DrawWithTooltips {
|
||||||
pub fn new(ctx: &EventCtx, batch: GeomBatch, tooltips: Vec<(Polygon, Text)>) -> Widget {
|
pub fn new(
|
||||||
|
ctx: &EventCtx,
|
||||||
|
batch: GeomBatch,
|
||||||
|
tooltips: Vec<(Polygon, Text)>,
|
||||||
|
hover: Box<dyn Fn(&Polygon) -> GeomBatch>,
|
||||||
|
) -> Widget {
|
||||||
Widget::new(Box::new(DrawWithTooltips {
|
Widget::new(Box::new(DrawWithTooltips {
|
||||||
dims: batch.get_dims(),
|
dims: batch.get_dims(),
|
||||||
top_left: ScreenPt::new(0.0, 0.0),
|
top_left: ScreenPt::new(0.0, 0.0),
|
||||||
|
hover,
|
||||||
draw: ctx.upload(batch),
|
draw: ctx.upload(batch),
|
||||||
tooltips,
|
tooltips,
|
||||||
}))
|
}))
|
||||||
@ -100,6 +107,8 @@ impl WidgetImpl for DrawWithTooltips {
|
|||||||
// TODO Assume regions are non-overlapping
|
// TODO Assume regions are non-overlapping
|
||||||
for (region, txt) in &self.tooltips {
|
for (region, txt) in &self.tooltips {
|
||||||
if region.contains_pt(translated) {
|
if region.contains_pt(translated) {
|
||||||
|
let extra = g.upload((self.hover)(region));
|
||||||
|
g.redraw_at(self.top_left, &extra);
|
||||||
g.draw_mouse_tooltip(txt.clone());
|
g.draw_mouse_tooltip(txt.clone());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ use crate::options::TrafficSignalStyle;
|
|||||||
use crate::render::draw_signal_phase;
|
use crate::render::draw_signal_phase;
|
||||||
use abstutil::prettyprint_usize;
|
use abstutil::prettyprint_usize;
|
||||||
use ezgui::{
|
use ezgui::{
|
||||||
Btn, Checkbox, Color, EventCtx, FanChart, GeomBatch, Line, PlotOptions, ScatterPlot, Series,
|
Btn, Checkbox, Color, DrawWithTooltips, EventCtx, FanChart, GeomBatch, Line, PlotOptions,
|
||||||
Text, Widget,
|
ScatterPlot, Series, Text, Widget,
|
||||||
};
|
};
|
||||||
use geom::{ArrowCap, Distance, Duration, PolyLine, Polygon, Time};
|
use geom::{ArrowCap, Distance, Duration, PolyLine, Polygon, Time};
|
||||||
use map_model::{IntersectionID, IntersectionType, PhaseType};
|
use map_model::{IntersectionID, IntersectionType, PhaseType};
|
||||||
@ -150,25 +150,22 @@ pub fn current_demand(
|
|||||||
let polygon = app.primary.map.get_i(id).polygon.clone();
|
let polygon = app.primary.map.get_i(id).polygon.clone();
|
||||||
let bounds = polygon.get_bounds();
|
let bounds = polygon.get_bounds();
|
||||||
// Pick a zoom so that we fit a fixed width in pixels
|
// Pick a zoom so that we fit a fixed width in pixels
|
||||||
let zoom = 300.0 / bounds.width();
|
let zoom = (0.25 * ctx.canvas.window_width) / bounds.width();
|
||||||
batch.push(app.cs.normal_intersection, polygon);
|
batch.push(
|
||||||
|
app.cs.normal_intersection,
|
||||||
|
polygon.translate(-bounds.min_x, -bounds.min_y).scale(zoom),
|
||||||
|
);
|
||||||
|
|
||||||
let mut txt_batch = GeomBatch::new();
|
let mut tooltips: Vec<(Polygon, Text)> = Vec::new();
|
||||||
for (pl, demand) in demand_per_group {
|
for (pl, demand) in demand_per_group {
|
||||||
let percent = (demand as f64) / (total_demand as f64);
|
let percent = (demand as f64) / (total_demand as f64);
|
||||||
batch.push(
|
let arrow = pl
|
||||||
Color::hex("#A3A3A3"),
|
.make_arrow(percent * Distance::meters(3.0), ArrowCap::Triangle)
|
||||||
pl.make_arrow(percent * Distance::meters(3.0), ArrowCap::Triangle),
|
.translate(-bounds.min_x, -bounds.min_y)
|
||||||
);
|
.scale(zoom);
|
||||||
txt_batch.append(
|
batch.push(Color::hex("#A3A3A3"), arrow.clone());
|
||||||
Text::from(Line(prettyprint_usize(demand)).fg(Color::RED))
|
tooltips.push((arrow, Text::from(Line(prettyprint_usize(demand)))));
|
||||||
.render_ctx(ctx)
|
|
||||||
.scale(0.15)
|
|
||||||
.centered_on(pl.middle()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
batch.append(txt_batch);
|
|
||||||
let batch = batch.translate(-bounds.min_x, -bounds.min_y).scale(zoom);
|
|
||||||
|
|
||||||
let mut txt = Text::from(Line(format!(
|
let mut txt = Text::from(Line(format!(
|
||||||
"Active agent demand at {}",
|
"Active agent demand at {}",
|
||||||
@ -183,7 +180,21 @@ pub fn current_demand(
|
|||||||
);
|
);
|
||||||
|
|
||||||
rows.push(
|
rows.push(
|
||||||
Widget::col(vec![txt.draw(ctx), Widget::draw_batch(ctx, batch)])
|
Widget::col(vec![
|
||||||
|
txt.draw(ctx),
|
||||||
|
DrawWithTooltips::new(
|
||||||
|
ctx,
|
||||||
|
batch,
|
||||||
|
tooltips,
|
||||||
|
Box::new(|arrow| {
|
||||||
|
let mut list = vec![(Color::hex("#EE702E"), arrow.clone())];
|
||||||
|
if let Ok(p) = arrow.to_outline(Distance::meters(1.0)) {
|
||||||
|
list.push((Color::WHITE, p));
|
||||||
|
}
|
||||||
|
GeomBatch::from(list)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
])
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.bg(app.cs.inner_panel)
|
.bg(app.cs.inner_panel)
|
||||||
.outline(2.0, Color::WHITE),
|
.outline(2.0, Color::WHITE),
|
||||||
|
@ -304,7 +304,7 @@ fn contingency_table(ctx: &mut EventCtx, app: &App, filter: &Filter) -> Widget {
|
|||||||
}
|
}
|
||||||
batch.extend(Color::BLACK, outlines);
|
batch.extend(Color::BLACK, outlines);
|
||||||
|
|
||||||
DrawWithTooltips::new(ctx, batch, tooltips)
|
DrawWithTooltips::new(ctx, batch, tooltips, Box::new(|_| GeomBatch::new()))
|
||||||
.container()
|
.container()
|
||||||
.outline(2.0, Color::WHITE)
|
.outline(2.0, Color::WHITE)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
|
Loading…
Reference in New Issue
Block a user