Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new graph layout: tree #91

Open
tonilastre opened this issue Feb 16, 2024 · 4 comments
Open

Add new graph layout: tree #91

tonilastre opened this issue Feb 16, 2024 · 4 comments

Comments

@tonilastre
Copy link
Contributor

It should be fairly simple to switch that using the Orb API.

@AlexIchenskiy
Copy link

I believe it's a good idea to create a layout interface with a single method that takes all nodes and returns newly calculated positions for them. These positions could then be applied to the simulator as fixed or sticky through the view, updating the rendered view accordingly.

Something like this implementation with an enum for available layouts, a described interface, and a generic layout implementation for parsing the input string is fairly straightforward to add new layouts and use them:

export enum layouts {
  DEFAULT = 'default',
  CIRCLE = 'circle',
  ...
}

export interface ILayout<N extends INodeBase, E extends IEdgeBase> {
  getPositions(nodes: INode<N, E>[], width: number, height: number): INodePosition[];
}

export class Layout<N extends INodeBase, E extends IEdgeBase> implements ILayout<N, E> {
  private readonly _layout: ILayout<N, E> | null;

  private layoutByLayoutName: Record<string, ILayout<N, E> | null> = {
    [layouts.DEFAULT]: null,
    [layouts.CIRCLE]: new CircleLayout(),
    ...
  };

  constructor(layoutName: string) {
    this._layout = this.layoutByLayoutName[layoutName];
  }

  getPositions(nodes: INode<N, E>[], width: number, height: number): INodePosition[] {
    return this._layout === null ? [] : this._layout.getPositions(nodes, width, height);
  }
}

It has to be integrated into orb view by setting fixed positions for all nodes on data setup or change like this:

if (this._settings.layout !== layouts.DEFAULT) {
  nodePositions = this._layout.getPositions(
    this._graph.getNodes(),
    this._renderer.width,
    this._renderer.height,
  );
}
this._simulator.setupData({ nodes: nodePositions, edges: edgePositions });

Where _layout is a private variable instantiated in the constructor:

this._layout = new Layout(this._settings.layout);

Example of a new layout:

export class CircleLayout<N extends INodeBase, E extends IEdgeBase> implements ILayout<N, E> {

  getPositions(nodes: INode<N, E>[], width: number, height: number): INodePosition[] {
    const nodePositions = /* calculate positions */
    return nodes.map((node, index) => {
      return nodePositions;
    });
  }

}

For now, it is just a proposal of a possible solution for integrating layouts into the orb and it requires a lot of debugging for different edge-cases (adding nodes when a layout is present, check for edges behaviour, adding physics etc.), so feel free to share any ideas and proposals :)

@josiahbryan
Copy link

Would love a tree layout! As it is now, I have to integrate an entire other library just for a tree view of my graph - yuck :-( Any plans to add this in?

@tonilastre
Copy link
Contributor Author

We will add this after we release orb 1.0.0. It's almost ready, we need to finish up the documentation. The branch is almost ready: #47

By the way, which library did you use for the tree layout? It will help us compare the layout output when we do the tree layout. Are you happy with the external library position output that you use?

@josiahbryan
Copy link

@tonilastre I used vis-network - and yes, positioning output somewhat happy - still was playing with the spacing/padding between nodes, but mostly okay. My dataset is somewhat corrupted right, else I'd share a screenshot.

However, I can share this gist that shows my usage of it - https://gist.github.com/josiahbryan/3b43e9be764d545eb7483cfb2cc2525b - the goal of that component was to be hot-swapable with my similarly-named CustomOrbGraph widget which wraps Orb obviously, so it mainly does the data manipulation to massage the data I give usually give Orb into a format that viz-network handles, and update it when it changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants