Izhaki / regraph

React graph components

Home Page:https://regraph.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[editor] Perform layout in editor

Izhaki opened this issue · comments

Currently with editor the layout is done using the connection layout within the hook chain of the graph constructor. Intended for static renders, this means that any change results in all the connections being resolved from scratch.

We want the layout to be done in the editor.

👱‍♀️Why?

The editor is change-aware, unlike hooks or HOCs which needs explicit checks to realise what have changed.

So for instance, if a node is moved we can only re-layout its connections.

👱‍♀️Can you not memoize this process?

We could, but it still means we have to check on every render.

Changes needed

Box requests as boxer props

Currently the layout is after (Boxer) in the hook chain and it fires up requests for boxing. This won't work with the editor as it needs to report down to Boxer.

  • Rename autoBox to boxer
  • Boxer to support incoming boxRequests

Unresolved connections filtering

Also, currently it is the layout hook that filters out unresolved connections. If the editor is the one doing the layouts, where do the unresolved connections go?

  • filterUnresolvedConnections hook -We could just introduce another hook that does this, but it'll have to happen on every render, which is not ideal.
  • graphConnect - We could do this in the graphConnect, it can look and see if there are any boxRequests and if there are filter unresolvedConnections.
  • Connections - We could have connections not rendering if they are not resolved, but this means unresolved connection are considered valid, which could yield unintended unresolved connections will raise no error.
  • We could just keep them outside of the connections slice in the editor.
    • This is best performance wise, but adds quite a bit of complexity.

⚠️ Connections may not resolve because one node is dragged over another (see layout code)

Meaning we can't rely on boxRequests to check if there are unresolved connections.

Layout could:

  • Return array of ids of unresolved connections (array.length to check if any are unresolved)
  • Stamp connection as unresolved: true + a flag.
  • Just a flag and the removal is done by checking if resolved again.

Layout api

We want to reuse as much of the layout code as possible - whether hook or used in the editor.

Recall that a layout takes a state and returns a modified state.

If we are to use it in the editor, it should return boxRequests as part of the state.

For static renders the order is this (and it must be this way because Boxer might be the boxes back-stop):

Boxer → layout

So the layout uses the Box context to fire up requests

But in the editor we have:

Editor (layout) → Boxer

Where the layout reports down.

So probably the layout should be oblivious to the Boxer context, just return boxRequests, which will then be fired up by the hook.

  • Extract any BoxContext related code from layout to the hook

Editor layout points

  • Initial state - probably just pass through the layout before giving to the store.
  • onBoxes
  • New connection
  • Box move

There are some serious questions around the layout API.

Currently we see a layout as a mapper of a graph (object) - it takes connections and boxes and returns laid-out connections.

Unresolved connections (and filtering them)

Now some connections may not be resolved. This can happen for two reasons:

  • Missing boxes
  • No resolution (the connection length is zero due to trimming when nodes overlap)

The main question is how and what the layout handle these.

Currently, when done in a hook, the layout filters out unresolved connections (note that there is an hook, which is different from the layout function). But this doesn't work for editor - what do we do with unresolved connections?

Possible solutions:

  • Mark connections as unresolved and filter later (in the graph maybe?)

Also in the editor we merge the connections that needed layout with those that didn't (that in itself is a map over all connections - unless they are stored as and object there).

👱‍♀️ Could we possibly give layout a predicate that tells it which connections need a layout? That way we won't have to map twice (we just update all connections).

Missing boxes

Both the hook and the editor can return missingBoxes.

  • Layout to map, graph to filter 'ignore'.
  • Layout to take (curry) getEndId and return missingBoxes. - Not THAT simple and best to leave this logic out of layout.
  • Layout take take needsResolution and only map connections that do.