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.
- TCA handles data and logic
- Cytoscape.js handles graph rendering
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.
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
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