network_graph 0.1.0

Network-style graph utilities and egui widget
Documentation
use eframe::egui;
use egui::{Color32, Sense, pos2};
use egui_network_map::{EdgeData, EdgeStyle, GraphWidget, NodeData, NodeStyle};
use rand::random_range;
use uuid::Uuid;

const CANVAS_SIZE: f32 = 5000.0;
const N_NODES: usize = 100;
const N_CONNS: usize = 100;

pub struct BasicNode {
    hover: bool,
}

impl NodeData for BasicNode {
    fn style(&self) -> NodeStyle {
        let mut style = NodeStyle::default();
        if self.hover {
            style.fill_color = Color32::RED;
            style.border_color = Color32::RED;
        }
        return style;
    }

    fn uuid(&self) -> Uuid {
        return Uuid::new_v4();
    }

    fn fixed(&self) -> bool {
        return false;
    }

    fn sense(&self) -> Option<Sense> {
        return Some(Sense::hover());
    }

    fn update(&mut self, sense_response: Option<egui::Response>) {
        self.hover = match sense_response {
            Some(response) => response.hovered(),
            None => false,
        };
    }
}

impl Default for BasicNode {
    fn default() -> Self {
        return BasicNode { hover: false };
    }
}

pub struct BasicEdge {
    hover: bool,
}

impl EdgeData<BasicNode> for BasicEdge {
    fn style(&self) -> EdgeStyle {
        let mut style = EdgeStyle::default();
        if self.hover {
            style.line_color = Color32::RED;
        }
        return style;
    }

    fn update(&mut self, node_1_data: &BasicNode, node_2_data: &BasicNode)
    where
        BasicNode: NodeData,
    {
        self.hover = node_1_data.hover || node_2_data.hover;
    }
}

impl Default for BasicEdge {
    fn default() -> Self {
        return BasicEdge { hover: false };
    }
}

fn main() -> eframe::Result<()> {
    let options = eframe::NativeOptions {
        run_and_return: true,
        viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 800.0]),
        ..Default::default()
    };

    let mut graph: GraphWidget<BasicNode, BasicEdge> = GraphWidget::default();

    let min = CANVAS_SIZE / -2.0;
    let max = CANVAS_SIZE / 2.0;
    let node_uuids: Vec<Uuid> = (0..N_NODES)
        .map(|_| {
            graph.new_node(
                BasicNode::default(),
                pos2(random_range(min..max), random_range(min..max)),
            )
        })
        .collect();
    let _edge_uuids: Vec<Uuid> = (0..N_CONNS)
        .map(|_| {
            graph
                .new_connection(
                    BasicEdge::default(),
                    *node_uuids.get(random_range(0..node_uuids.len())).unwrap(),
                    *node_uuids.get(random_range(0..node_uuids.len())).unwrap(),
                )
                .unwrap()
        })
        .collect();

    eframe::run_native(
        "First window",
        options.clone(),
        Box::new(|_cc| Ok(Box::new(ExampleApp { graph }))),
    )?;

    return Ok(());
}

pub struct ExampleApp {
    graph: GraphWidget<BasicNode, BasicEdge>,
}

impl eframe::App for ExampleApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| ui.add(&mut self.graph));
    }
}