feat: add 3D toggle and adjust theme
This commit is contained in:
parent
5405c3e12f
commit
13bb965b28
71
src/App.css
71
src/App.css
@ -23,6 +23,77 @@ footer {
|
|||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
z-index: 9;
|
||||||
|
position: absolute;
|
||||||
|
top: 24;
|
||||||
|
left: 24;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.control {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The switch - the box around the slider */
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
width: 68px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide default HTML checkbox */
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The slider */
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 34px;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked+.slider {
|
||||||
|
background-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus+.slider {
|
||||||
|
box-shadow: 0 0 1px #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked+.slider:before {
|
||||||
|
-webkit-transform: translateX(26px);
|
||||||
|
-ms-transform: translateX(26px);
|
||||||
|
transform: translateX(26px);
|
||||||
|
}
|
||||||
|
|
||||||
.grey {
|
.grey {
|
||||||
color: #444;
|
color: #444;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||||
import { apiAuth } from "./api";
|
import { apiAuth } from "./api";
|
||||||
import { GraphCanvas, GraphCanvasRef, GraphEdge, GraphNode, useSelection } from "reagraph";
|
import { GraphCanvas, GraphCanvasRef, GraphEdge, GraphNode, recommendLayout, useSelection } from "reagraph";
|
||||||
|
import { customTheme } from "./NetworkTheme";
|
||||||
|
|
||||||
interface NetworkData {
|
interface NetworkData {
|
||||||
nodes: GraphNode[],
|
nodes: GraphNode[],
|
||||||
@ -10,6 +11,7 @@ interface NetworkData {
|
|||||||
export const GraphComponent = () => {
|
export const GraphComponent = () => {
|
||||||
const [data, setData] = useState({ nodes: [], edges: [] } as NetworkData);
|
const [data, setData] = useState({ nodes: [], edges: [] } as NetworkData);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [threed, setThreed] = useState(false);
|
||||||
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -26,20 +28,46 @@ export const GraphComponent = () => {
|
|||||||
ref: graphRef,
|
ref: graphRef,
|
||||||
nodes: data.nodes,
|
nodes: data.nodes,
|
||||||
edges: data.edges,
|
edges: data.edges,
|
||||||
pathSelectionType: 'out'
|
pathSelectionType: 'out',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleThreed() {
|
||||||
|
setThreed(!threed)
|
||||||
|
graphRef.current?.fitNodesInView();
|
||||||
|
graphRef.current?.centerGraph();
|
||||||
|
graphRef.current?.resetControls();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GraphCanvas
|
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
|
||||||
draggable
|
<div className="controls" >
|
||||||
ref={graphRef}
|
<div className="control" onClick={handleThreed}>
|
||||||
nodes={data.nodes}
|
<span>2D</span>
|
||||||
edges={data.edges}
|
<div className="switch">
|
||||||
selections={selections}
|
<input type="checkbox" checked={threed} />
|
||||||
actives={actives}
|
<span className="slider round"></span>
|
||||||
onCanvasClick={onCanvasClick}
|
</div>
|
||||||
onNodeClick={onNodeClick}
|
<span>3D</span>
|
||||||
/>
|
</div>
|
||||||
|
</div>
|
||||||
|
<GraphCanvas
|
||||||
|
draggable
|
||||||
|
cameraMode={threed ? "rotate" : "pan"}
|
||||||
|
layoutType={threed ? "forceDirected3d" : "forceDirected2d"}
|
||||||
|
layoutOverrides={{
|
||||||
|
linkDistance: 200
|
||||||
|
}}
|
||||||
|
labelType="auto"
|
||||||
|
ref={graphRef}
|
||||||
|
theme={customTheme}
|
||||||
|
nodes={data.nodes}
|
||||||
|
edges={data.edges}
|
||||||
|
selections={selections}
|
||||||
|
actives={actives}
|
||||||
|
onCanvasClick={onCanvasClick}
|
||||||
|
onNodeClick={onNodeClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
59
src/NetworkTheme.tsx
Normal file
59
src/NetworkTheme.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Theme } from "reagraph";
|
||||||
|
|
||||||
|
export const customTheme: Theme = {
|
||||||
|
canvas: {
|
||||||
|
background: 'aliceblue',
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
fill: '#69F',
|
||||||
|
activeFill: '#36C',
|
||||||
|
opacity: 1,
|
||||||
|
selectedOpacity: 1,
|
||||||
|
inactiveOpacity: 0.333,
|
||||||
|
label: {
|
||||||
|
color: '#404040',
|
||||||
|
stroke: 'white',
|
||||||
|
activeColor: 'black'
|
||||||
|
},
|
||||||
|
subLabel: {
|
||||||
|
color: '#ddd',
|
||||||
|
stroke: 'transparent',
|
||||||
|
activeColor: '#1DE9AC'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lasso: {
|
||||||
|
border: '1px solid #55aaff',
|
||||||
|
background: 'rgba(75, 160, 255, 0.1)'
|
||||||
|
},
|
||||||
|
ring: {
|
||||||
|
fill: '#69F',
|
||||||
|
activeFill: '#36C'
|
||||||
|
},
|
||||||
|
edge: {
|
||||||
|
fill: '#bed4ff',
|
||||||
|
activeFill: '#36C',
|
||||||
|
opacity: 1,
|
||||||
|
selectedOpacity: 1,
|
||||||
|
inactiveOpacity: 0.2,
|
||||||
|
label: {
|
||||||
|
stroke: '#fff',
|
||||||
|
color: '#2A6475',
|
||||||
|
activeColor: '#1DE9AC',
|
||||||
|
fontSize: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
fill: '#bed4ff',
|
||||||
|
activeFill: '#36C'
|
||||||
|
},
|
||||||
|
cluster: {
|
||||||
|
stroke: '#D8E6EA',
|
||||||
|
opacity: 1,
|
||||||
|
selectedOpacity: 1,
|
||||||
|
inactiveOpacity: 0.1,
|
||||||
|
label: {
|
||||||
|
stroke: '#fff',
|
||||||
|
color: '#2A6475'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user