summaryrefslogtreecommitdiff
path: root/app/components
diff options
context:
space:
mode:
authorThomas F. K. Jorna <[email protected]>2021-07-15 15:06:41 +0200
committerThomas F. K. Jorna <[email protected]>2021-07-15 15:06:41 +0200
commite4249979b67127dbeaf8d78bab6500154dcf6cde (patch)
tree26289ccede62b038a737d91deda88762fdafc69d /app/components
parent3de8a0a99f74cef8032d718e4b51d5c9c364db56 (diff)
added 3d and expandable mode
Diffstat (limited to 'app/components')
-rw-r--r--app/components/graph/graph.tsx65
-rw-r--r--app/components/tweaks/tweaks.tsx36
2 files changed, 87 insertions, 14 deletions
diff --git a/app/components/graph/graph.tsx b/app/components/graph/graph.tsx
index 934901f..7a4843b 100644
--- a/app/components/graph/graph.tsx
+++ b/app/components/graph/graph.tsx
@@ -1,5 +1,5 @@
import * as React from "react"
-import { useState, useEffect, useRef } from "react"
+import { useState, useEffect, useRef, useMemo, useCallback } from "react"
import { StyleProp, TextStyle, View, ViewStyle } from "react-native"
import { observer } from "mobx-react-lite"
import { color, typography } from "../../theme"
@@ -8,7 +8,9 @@ import { flatten } from "ramda"
//import data from "../../data/miserables.json"
//import genRandomTree from "../../data/randomdata";
-import rando from "../../data/rando.json"
+//import rando from "../../data/rando.json"
+import rando from "../../data/randorev.json"
+
import { ForceGraph2D, ForceGraph3D, ForceGraphVR, ForceGraphAR } from 'react-force-graph';
import * as d3 from "d3-force";
@@ -58,17 +60,72 @@ export const Graph = observer(function Graph(props: GraphProps) {
fg.d3Force('charge').strength(physics.charge);
});
+ const rootId = 0;
+
+ const nodesById = useMemo(() => {
+ const nodesById = Object.fromEntries(rando.nodes.map(node => [node.id, node]));
+
+ // link parent/children
+ rando.nodes.forEach(node => {
+ node.collapsed = node.id !== rootId;
+ node.childLinks = [];
+ });
+ rando.links.forEach(link => nodesById[link.source].childLinks.push(link));
+
+ return nodesById;
+ }, [rando]);
+
+ const getPrunedTree = useCallback(() => {
+ const visibleNodes = [];
+ const visibleLinks = [];
+ (function traverseTree(node = nodesById[rootId]) {
+ visibleNodes.push(node);
+ if (node.collapsed) return;
+ visibleLinks.push(...node.childLinks);
+ node.childLinks
+ .map(link => ((typeof link.target) === 'object') ? link.target : nodesById[link.target]) // get child node
+ .forEach(traverseTree);
+ })();
+
+ return { nodes: visibleNodes, links: visibleLinks };
+ }, [nodesById]);
+
+ const [prunedTree, setPrunedTree] = useState(getPrunedTree());
+
+ const handleNodeClick = useCallback(node => {
+ node.collapsed = !node.collapsed; // toggle collapse state
+ setPrunedTree(getPrunedTree())
+ }, []);
+
return (
<View>
+ {!physics.threedim ?
<ForceGraph2D
ref={fgRef}
- graphData={rando}
- nodeAutoColorBy={d => d.id%GROUPS}
+ graphData={physics.collapse ? prunedTree : rando}
+ // nodeAutoColorBy={d => d.id%GROUPS}
+ linkAutoColorBy={d => rando.nodes[d.source].id%GROUPS}
+ linkColor={"#ffffff"}
+ linkWidth={2}
+ linkDirectionalParticles={2}
+ nodeColor={node => !node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow'}
+ onNodeClick={handleNodeClick}
+ //d3VelocityDecay={visco}
+ />
+ :
+ <ForceGraph3D
+ ref={fgRef}
+ graphData={physics.collapse ? prunedTree : rando}
+ // nodeAutoColorBy={d => d.id%GROUPS}
linkAutoColorBy={d => rando.nodes[d.source].id%GROUPS}
linkColor={"#ffffff"}
linkWidth={2}
+ linkDirectionalParticles={2}
+ nodeColor={node => !node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow'}
+ onNodeClick={handleNodeClick}
//d3VelocityDecay={visco}
/>
+ }
</View>
)
})
diff --git a/app/components/tweaks/tweaks.tsx b/app/components/tweaks/tweaks.tsx
index d1c8c2a..e7bbd6f 100644
--- a/app/components/tweaks/tweaks.tsx
+++ b/app/components/tweaks/tweaks.tsx
@@ -34,29 +34,45 @@ export const Tweaks = observer(function Tweaks(props: TweaksProps) {
const styles = flatten([CONTAINER, style])
return (
- <>
- <Slider style={{ position: "absolute", top: 50, zIndex: 100, width: "20%", height: 40 }}
- minimumValue={-100}
+ <View style={{position: "absolute", top: 50, left: 50, zIndex: 100, width: "20%"}}>
+ <Text preset="fieldLabel" text={"Repulsive force: " + physics.charge}/>
+ <Slider style={{height: 40 , width: "90%"}}
+ minimumValue={-400}
maximumValue={0}
onValueChange={(value) => { setPhysics({...physics, charge: value}) }}
value={physics.charge}
step={1}/>
- <Slider style={{ position: "absolute", top: 100, zIndex: 100, width: "20%", height: 40 }}
+ <Text preset="fieldLabel" text={"Link Force: " + physics.linkStrength}/>
+ <Slider style={{height: 40 , width: "90%"}}
minimumValue={0}
- maximumValue={10}
+ maximumValue={2}
onValueChange={(value) => { setPhysics({...physics, linkStrength: value}) }}
value={physics.linkStrength}
- step={1}/>
- <Slider style={{ position: "absolute", top: 150, zIndex: 100, width: "20%", height: 40 }}
+ step={0.1}
+ />
+ <Text preset="fieldLabel" text={"'Link Iterations': " + physics.linkIts}/>
+ <Slider style={{ height: 40 , width: "90%"}}
minimumValue={1}
- maximumValue={5}
+ maximumValue={10}
onValueChange={(value) => { setPhysics({...physics, linkIts: value}) }}
value={physics.linkIts}
step={1}/>
- <Switch style={{ position: "absolute", top: 200, zIndex: 100, width: "5", height: 40 }}
+ <Text preset="fieldLabel" text="Collision"/>
+ <Switch style={{width: "5", height: 20 }}
value={physics.collision}
onValueChange={()=>{setPhysics({...physics, collision: !physics.collision})}}
/>
- </>
+
+ <Text preset="fieldLabel" text="Expandable Graph"/>
+ <Switch style={{width: "5", height: 20 }}
+ value={physics.collapse}
+ onValueChange={()=>{setPhysics({...physics, collapse: !physics.collapse})}}
+ />
+ <Text preset="fieldLabel" text="3D"/>
+ <Switch style={{width: "5", height: 20 }}
+ value={physics.threedim}
+ onValueChange={()=>{setPhysics({...physics, threedim: !physics.threedim})}}
+ />
+ </View>
)
})