egui_graphs 0.9.0

Interactive graph visualization widget for rust powered by egui
Documentation
use egui::Pos2;

use petgraph::{
    prelude::GraphMap,
    stable_graph::{EdgeIndex, EdgeReference, NodeIndex, StableGraph},
    visit::{EdgeRef, IntoEdgeReferences, IntoNodeReferences},
    Direction, EdgeType,
};

use crate::{metadata::Metadata, state_computed::StateComputed, transform, Edge, Node};

/// Graph type compatible with [`super::GraphView`].
pub struct Graph<N: Clone, E: Clone, Ty: EdgeType> {
    pub g: StableGraph<Node<N>, Edge<E>, Ty>,
}

impl<N: Clone, E: Clone, Ty: EdgeType> From<&StableGraph<N, E, Ty>> for Graph<N, E, Ty> {
    fn from(value: &StableGraph<N, E, Ty>) -> Self {
        transform::to_graph(value)
    }
}

// impl<N: Clone, E: Clone, Ty: EdgeType> From<&GraphMap<N, E, Ty>> for Graph<N, E, Ty> {
//     fn from(value: &GraphMap<N, E, Ty>) -> Self {
//         transform::to_graph(value.into_graph())
//     }
// }

impl<'a, N: Clone, E: Clone, Ty: EdgeType> Graph<N, E, Ty> {
    pub fn new(g: StableGraph<Node<N>, Edge<E>, Ty>) -> Self {
        Self { g }
    }

    /// Iterates over all nodes and edges and calls the walker function.
    pub fn walk(
        &self,
        mut walker: impl FnMut(
            &Self,
            Option<&NodeIndex>,
            Option<&Node<N>>,
            Option<&EdgeIndex>,
            Option<&Edge<E>>,
        ),
    ) {
        self.nodes_iter()
            .for_each(|(idx, n)| walker(self, Some(&idx), Some(n), None, None));
        self.edges_iter()
            .for_each(|(idx, e)| walker(self, None, None, Some(&idx), Some(e)));
    }

    /// Finds node by position. Can be optimized by using a spatial index like quad-tree if needed.
    pub fn node_by_pos(
        &self,
        comp: &'a StateComputed,
        meta: &'a Metadata,
        pos: Pos2,
    ) -> Option<(NodeIndex, &Node<N>)> {
        let pos_in_graph = (pos - meta.pan).to_vec2() / meta.zoom;
        self.nodes_iter().find(|(idx, n)| {
            let comp_node = comp.node_state(idx).unwrap();
            let dist_to_node = (n.location() - pos_in_graph).length();
            let node_rad = comp_node.radius / meta.zoom;
            dist_to_node <= node_rad
        })
    }

    pub fn g(&mut self) -> &mut StableGraph<Node<N>, Edge<E>, Ty> {
        &mut self.g
    }

    ///Provides iterator over all nodes and their indices.
    pub fn nodes_iter(&'a self) -> impl Iterator<Item = (NodeIndex, &Node<N>)> {
        self.g.node_references()
    }

    /// Provides iterator over all edges and their indices.
    pub fn edges_iter(&'a self) -> impl Iterator<Item = (EdgeIndex, &Edge<E>)> {
        self.g.edge_references().map(|e| (e.id(), e.weight()))
    }

    pub fn node(&self, i: NodeIndex) -> Option<&Node<N>> {
        self.g.node_weight(i)
    }

    pub fn edge(&self, i: EdgeIndex) -> Option<&Edge<E>> {
        self.g.edge_weight(i)
    }

    pub fn edge_endpoints(&self, i: EdgeIndex) -> Option<(NodeIndex, NodeIndex)> {
        self.g.edge_endpoints(i)
    }

    pub fn node_mut(&mut self, i: NodeIndex) -> Option<&mut Node<N>> {
        self.g.node_weight_mut(i)
    }

    pub fn is_directed(&self) -> bool {
        self.g.is_directed()
    }

    pub fn edges_num(&self, idx: NodeIndex) -> usize {
        self.g.edges(idx).count()
    }

    pub fn edges_directed(
        &self,
        idx: NodeIndex,
        dir: Direction,
    ) -> impl Iterator<Item = EdgeReference<Edge<E>>> {
        self.g.edges_directed(idx, dir)
    }
}