Skip to content

arniebradfo/RedEye-Graph

 
 

Repository files navigation

RedEye Hierarchical Graph

The RedEye Graph has three main functional parts:

  • The HierarchicalGraphData store - responsible for parsing the hierarchical graph data, storing state, and issuing state change events
  • The multiple GraphRenderer - responsible for d3 force-directed simulations and layout
  • The GraphHandler - responsible for managing the relationships between the HierarchicalGraphData store and all the GraphRenderers

GraphHandler

The GraphHandler manages relationships between the HierarchicalGraphData store and all the GraphRenderers. It also handles global d3 based events like pan, zoom, drag, and text occlusion.

Events update state in the following order:

  1. d3 events (click, hover, drag) occur in the GraphHierarchical renderers, wired to methods of the GraphHandler.
  2. The GraphHandler calls update methods on the HierarchicalGraphData store.
  3. HierarchicalGraphData store updates the relevant data, and fires an on{Data}Change event to the GraphHandler
  4. The GraphHandler calls update methods on the GraphHierarchical renderers to update the relevant visual aspects

This circular flow provides consistent data and visual updates (steps 3 & 4) when HierarchicalGraphData update methods are called from outside the GraphHandler (instead of step 2). S

HierarchicalGraphData Store

The Hierarchial GraphData class is responsible for parsing unstructured data in to the correct format, and for maintaining interaction state state via methods and events

Parsing

The hierarchicalGraphDataParser combines a parent-child hierarchical tree graph data structure with an unstructured node-link graph.

TODO: this is a super confusing explanation. This needs to be combined with the Terms section, cross linked with the code, and some diagrams would probably be helpful.

GraphData is supplied to the initial parser that will produce serializable js object. This Serializable object can optionally contain the predefined x,y coordinates of each node to restore an pre-existing layout. The resulting serializable data is then passed to a stratify method that replaces string id references with pointers to their respective js objects.

The parsing groups nodes based on their given 'parent' id. This parsing also creates a third intermediary level that further groups nodes within each parent based on their 'signature.' A signature is a property given to a node based on how it shares links to other nodes on the parent level, ie how it connects to a cousin node: through its parent to its uncle to its uncle's child, the cousin. This grouping can significant simplify the simulation computation required to layout the nodes by drawing all grouped child nodes as a single unit.

The resulting data is a combination of two trees. Each tree having four levels: root > super > group > sub

  • a node-link-tree - with each tree-node containing child nodes links between those child noes. This data is used to power each nested d3 node-link simulation layout.
  • a link-tree - where each tree-node is a link containing the sub simulation's child links.

These two trees are blended together where

  • each link in the node-link-tree is a node in the link-tree
  • each the source-node and target-node of each link in the link-tree are nodes in the node-link-tree

There is an additional base-link data item representing the original link between to nodes before parsing occurred. These base links contain references to two leaf nodes of the link-tree representing the lowest level of the subdivided link. The ancestors of these two leaves will contain the full visual link between any two nodes in the hierarchical graph.

Terms

  • Hierarchical Prefixes
    • Root - A single node that is the root of the tree hierarchy
    • Super - The top level of hierarchy representing nodes that contain sets of child subnodes. These are machines,computers,hosts,servers,etc...
    • Group - The middle level of the hierarchy representing 'groups' of subnodes. This level is generated during data parsing to group subnodes a common 'link signature.' Read more about signatures [HERE].
    • Sub - The bottom level of the hierarchy.
  • BaseLink - the original link between 2 nodes before parsing in the data structure. this is not directly visualized, but contains references to all ParentLinks and SiblingLinks at all levels of the graph that represent that BaseLink
  • BaseNode - an original Node - same as a SubNode
  • KeyNode - a node meant to be visualized. ie not a ParentLinkNode
  • SiblingLink - a link between 2 KeyNodes that share a parent
  • ParentLink - a link between a KeyNode and a ParentLinkNode
  • ParentLinkNode - a node representing a SiblingLink between a parent node and an uncle node. This node type's x,y coordinates are determined by the layout of the parent simulation's related SiblingLink

Updating state

The responsibility for updating the HierarchicalGraphData state is shared between the HierarchicalGraphData and the GraphRenderer simulations.

  • HierarchicalGraphData is responsible for updating Interaction and Time states
    • Interaction state - Preview, Selected - which are analogous to hover and click respectively
    • Time state - Past, Present, Future - which are analogous to a beacon being dead, active, or future respectively
  • GraphRenderers are responsible for updating the layout properties from d3's SimulationNodeDatum and SimulationLinkDatum: x, y, vx, vy, fx, fy, and r.

GraphRenderers

HierarchicalGraphRenderers use d3 force directed simulations to render a node link diagram of their data and also to create a nested set of child HierarchicalGraphRenderers where appropriate.

Types

There are 3 GraphRenderers that extend an 'abstract' HierarchicalGraphRenderer base class. They follow the same hierarchical structure as the HierarchicalGraphData:

  • SuperGraphRenderer - renders the master graph. Nodes are 'expandable,' and hide/show their contents on interaction.
  • GroupGraphRenderer - responsible for visually grouping the SubNodes. These nodes are not intractable, and only exist to improve layout and render performance.
  • SubGraphRenderer - These node's have a much more forgiving force layout, typically ending up in an evenly dispersed cloud. Dragging one of these nodes actually moves its parent GroupGraphRenderer node.
  • (The GraphHandler manages the Root data node)

Simulation

The graph layout is computed using d3 force directed simulations. The forces applied are different for each GraphRenderer type, but the alpha related settings are kept in sync for all GraphRenderers via the HierarchicalGraphRenderer base class. There are also methods for managing the starting and stopping the simulation: reheat, cool, and freeze.

Performance

Chunking the simulations into a hierarchical tree reduces the number of objects in each simulation. Simulations perform a many-to-many comparison for each tick at O(n!), so the fewer the objects, the better the performance. While the simulation performance is still a major consideration, they only calculate the x,y coordinates and run relatively quickly. The svg DOM update cycle is much slower. DOM update performance is improved here by removing non-visible elements from the DOM tree. See the hideLayout/showLayout rendering methods below.

Rendering

Typically referred to as Draw{Method} in the code, these methods control the layout and styling of svg via d3's declarative selection chains.

There are several types of DrawMethods responsible for different types of rendering updates:

  • drawLayout - updates the x,y layout when any simulation updates occur
  • drawInteraction state - updates the interaction classes (preview and selection) based on the current data state
  • drawTime state - updates the time classes (past, present, future) based on the current data state
  • hideLayout / showLayout - Removes the graph from the DOM tree to improve performance and visualization legibility

Each Draw methods also has an option to recursively draw updates to all its children, typically referred to as {drawMethod}AllChildren.

Other

Text Occlusion

  • The textOcclusion utility manages hiding text for all rendered text in all GraphRenderers after each layout. It is managed by the GraphHandler

CSS

There is no exported default style.css sheet. The one in this project is for testing purposes only. a js object of css classNames is exported instead as RedEyeGraphClassNames.

Languages

  • CSS 76.7%
  • TypeScript 23.2%
  • Other 0.1%