Skip to content

Commit

Permalink
Implement level-of-detail on text labels
Browse files Browse the repository at this point in the history
  • Loading branch information
grtlr committed Dec 13, 2024
1 parent a02c262 commit f8e0110
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
72 changes: 66 additions & 6 deletions crates/viewer/re_view_graph/src/ui/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl DrawableLabel {
}

pub struct TextLabel {
color: Option<Color32>,
frame: Frame,
galley: Arc<Galley>,
}
Expand All @@ -44,11 +45,27 @@ pub struct CircleLabel {
color: Option<Color32>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum LevelOfDetail {
Full,
Low,
}

impl LevelOfDetail {
pub fn from_scaling(zoom: f32) -> Self {
if zoom < 0.20 {
Self::Low
} else {
Self::Full
}
}
}

impl DrawableLabel {
pub fn size(&self) -> Vec2 {
match self {
Self::Circle(CircleLabel { radius, .. }) => Vec2::splat(radius * 2.0),
Self::Text(TextLabel { galley, frame }) => {
Self::Text(TextLabel { galley, frame, .. }) => {
frame.inner_margin.sum() + galley.size() + Vec2::splat(frame.stroke.width * 2.0)
}
}
Expand Down Expand Up @@ -82,7 +99,11 @@ impl DrawableLabel {
.fill(ui.style().visuals.widgets.noninteractive.bg_fill)
.stroke(Stroke::new(1.0, ui.style().visuals.text_color()));

Self::Text(TextLabel { frame, galley })
Self::Text(TextLabel {
frame,
galley,
color,
})
}
}

Expand Down Expand Up @@ -115,7 +136,7 @@ fn draw_circle_label(
}

fn draw_text_label(ui: &mut Ui, label: &TextLabel, highlight: InteractionHighlight) -> Response {
let TextLabel { galley, frame } = label;
let TextLabel { galley, frame, .. } = label;
let visuals = &ui.style().visuals;

let bg = match highlight.hover {
Expand All @@ -137,12 +158,47 @@ fn draw_text_label(ui: &mut Ui, label: &TextLabel, highlight: InteractionHighlig
.inner
}

fn draw_rect_label(ui: &mut Ui, label: &TextLabel, highlight: InteractionHighlight) -> Response {
let TextLabel {
galley,
frame,
color,
} = label;
let visuals = &ui.style().visuals;

let bg = match highlight.hover {
HoverHighlight::None => visuals.widgets.noninteractive.bg_fill,
HoverHighlight::Hovered => visuals.widgets.hovered.bg_fill,
};

let stroke = match highlight.selection {
SelectionHighlight::Selection => visuals.selection.stroke,
_ => Stroke::new(1.0, visuals.text_color()),
};

// We use `gamma` to correct for the fact that text is not completely solid.
let fill_color = color
.unwrap_or_else(|| visuals.text_color())
.gamma_multiply(0.5);

frame
.stroke(stroke)
.fill(bg)
.show(ui, |ui| {
let (resp, painter) = ui.allocate_painter(galley.rect.size(), Sense::click());
painter.rect_filled(resp.rect, 0.0, fill_color);
resp
})
.inner
}

/// Draws a node at the given position.
fn draw_node(
ui: &mut Ui,
center: Pos2,
node: &DrawableLabel,
highlight: InteractionHighlight,
lod: LevelOfDetail,
) -> Response {
let builder = UiBuilder::new()
.max_rect(Rect::from_center_size(center, node.size()))
Expand All @@ -152,7 +208,10 @@ fn draw_node(

match node {
DrawableLabel::Circle(label) => draw_circle_label(&mut node_ui, label, highlight),
DrawableLabel::Text(label) => draw_text_label(&mut node_ui, label, highlight),
DrawableLabel::Text(label) if lod == LevelOfDetail::Full => {
draw_text_label(&mut node_ui, label, highlight)
}
DrawableLabel::Text(label) => draw_rect_label(&mut node_ui, label, highlight),
};

node_ui.response()
Expand Down Expand Up @@ -281,6 +340,7 @@ pub fn draw_graph(
graph: &Graph,
layout: &Layout,
query: &ViewQuery<'_>,
lod: LevelOfDetail,
) -> Rect {
let entity_path = graph.entity();
let entity_highlights = query.highlights.entity_highlight(entity_path.hash());
Expand All @@ -294,7 +354,7 @@ pub fn draw_graph(
let response = match node {
Node::Explicit { instance, .. } => {
let highlight = entity_highlights.index_highlight(instance.instance_index);
let mut response = draw_node(ui, center, node.label(), highlight);
let mut response = draw_node(ui, center, node.label(), highlight, lod);

let instance_path =
InstancePath::instance(entity_path.clone(), instance.instance_index);
Expand Down Expand Up @@ -322,7 +382,7 @@ pub fn draw_graph(
response
}
Node::Implicit { graph_node, .. } => {
draw_node(ui, center, node.label(), Default::default()).on_hover_text(format!(
draw_node(ui, center, node.label(), Default::default(), lod).on_hover_text(format!(
"Implicit node {} created via a reference in a GraphEdge component",
graph_node.as_str(),
))
Expand Down
2 changes: 1 addition & 1 deletion crates/viewer/re_view_graph/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod draw;
mod selection;
mod state;

pub use draw::{draw_debug, draw_graph, DrawableLabel};
pub use draw::{draw_debug, draw_graph, DrawableLabel, LevelOfDetail};
pub use selection::view_property_force_ui;
pub use state::GraphViewState;
6 changes: 4 additions & 2 deletions crates/viewer/re_view_graph/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use re_viewport_blueprint::ViewProperty;
use crate::{
graph::Graph,
layout::{ForceLayoutParams, LayoutRequest},
ui::{draw_debug, draw_graph, view_property_force_ui, GraphViewState},
ui::{draw_debug, draw_graph, view_property_force_ui, GraphViewState, LevelOfDetail},
visualizers::{merge, EdgesVisualizer, NodeVisualizer},
};

Expand Down Expand Up @@ -190,11 +190,13 @@ Display a graph of nodes and edges.
// We store a copy of the transformation to see if it has changed.
let ui_from_world_ref = ui_from_world;

let level_of_detail = LevelOfDetail::from_scaling(ui_from_world.scaling);

let resp = zoom_pan_area(ui, rect_in_ui, &mut ui_from_world, |ui| {
let mut world_bounding_rect = egui::Rect::NOTHING;

for graph in &graphs {
let graph_rect = draw_graph(ui, ctx, graph, layout, query);
let graph_rect = draw_graph(ui, ctx, graph, layout, query, level_of_detail);
world_bounding_rect = world_bounding_rect.union(graph_rect);
}

Expand Down

0 comments on commit f8e0110

Please sign in to comment.