diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/components/graph/graph.tsx | 65 | ||||
-rw-r--r-- | app/components/tweaks/tweaks.tsx | 36 | ||||
-rw-r--r-- | app/screens/graph/graph-screen.tsx | 4 |
3 files changed, 90 insertions, 15 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> ) }) diff --git a/app/screens/graph/graph-screen.tsx b/app/screens/graph/graph-screen.tsx index bba2955..9dc7c90 100644 --- a/app/screens/graph/graph-screen.tsx +++ b/app/screens/graph/graph-screen.tsx @@ -32,7 +32,9 @@ export const GraphScreen = observer(function GraphScreen() { charge: -30, collision: false, linkStrength: 1, - linkIts: 1 + linkIts: 1, + collapse: false, + threedim: false }); const gData = genRandomTree(); |