TCA for Network Graph via Cytoscape.js

mein
4 min readNov 7, 2023

Graph data, topology and network science are becoming more and more important. How to make SwiftUI interact with graph data? Here is a solution combing TCA and Cytoscape.js.

Referring to TCA+SwiftUI+Javascript, step 1, TCA+SwiftUI+Javascript, step 2, TCA+SwiftUI+Javascript, step 3, we are ready to integrate TCA with a real Javascript library, Cytoscape.js.

TCA Nested Reducers

TCA is good for designing nested reducers. Nested reducers are like different layers in a protocol.

The key point is to separate the ApplicationReducer with the CyGraphDataReducer.

Why do we need the ApplicationReducer?

Because the topology logic is different in each application.

For example,

  • node toggle: How many nodes are affected by the toggled node?
  • circular relation check: If adding a new edge will form a close loop, is it acceptable?

The ApplicationReducer And the CyGraphDataReducer handle different States.

  • ApplicationReducer.State contains all the data
  • CyGraphDataReducer.State contains only the visible data on the graph

The SwiftUICytoscape Package

Since we separate the topology logic with the Cytoscape graph data, we can make it a package without depending on any topology logic.

Examples

Single Parent, Toggle-enabled Graph

Each node has at maximum 1 parent node. This graph behaviors like a tree.

The SingleParentToggleGraphDataReducer handles the topology logic,

  • Circular loop is not acceptable.
  • If a node is toggled, all its descendant nodes are invisible.
  • If a node is expanded, all its ascendant nodes are expanded.
  • If a node is expanded, all its direct child nodes are visible.

Source code is here.

Multi Parents, Toggle-enabled Graph

Each node can have multiple parent nodes. This graph behaviors like a network.

The MultiParentToggleGraphDataReducer handles the topology logic,

  • Circular loop is not acceptable.
  • If a node is toggled, all its descendant edges are invisible.
  • If a node is expanded, all its ascendant edges are visible.
  • If a node is expanded, all its direct child edges are visible.
  • The node status is determined by the status of its connected edges.
    - fullyExpanded: if all edges are visible
    - toggle: if all ascendant edges are visible, while all descendant edges are invisible.
    - uptrace: if all ascendant edges are visible, while some descendant edges are invisible.
    - placeHolder: if some ascendant edges are invisible and some descendant edges are invisible, too.
    - hidden: if all edges are invisible

Source code is here.

The SwiftUICytoscape Package Source Code

Notes

  • The SwiftUICytoscape Package works on Swift Playgrounds, too.
  • WebKit and Javascript
    Some corner cases need to take care of,
    - window.devicePixelRatio causes “Total canvas memory use exceeds the maximum limit” (https://github.com/wojtekmaj/react-pdf/issues/1020)
    - click event or tap event?
    It depends on OS version, not WebKit’s navigator.userAgent
OS    | environment        |navigator.userAgent    |click or tap
------+--------------------+-----------------------+------------
iPadOS| Swift Playground |Macintosh; Intel Mac OS|tap
------+--------------------+-----------------------+------------
iPadOS| App |Macintosh; Intel Mac OS|tap
------+--------------------+-----------------------+------------
iPadOS| Simulator |Macintosh; Intel Mac OS|tap
------+--------------------+-----------------------+------------
iOS | Simulator |iPhonel; CPU iPhone OS |tap
------+--------------------+-----------------------+------------
macOS |App(Design for iPad)|Macintosh; Intel Mac OS|tap and click

--

--