react-force-graph-3d
Version:
React component for 3D force directed graphs
180 lines (156 loc) • 7.57 kB
TypeScript
import * as React from 'react';
import { Object3D, Material, Light, Scene, Camera, WebGLRenderer } from 'three';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { ConfigOptions, ForceGraph3DInstance } from '3d-force-graph';
interface GraphData<NodeType = {}, LinkType = {}> {
nodes: NodeObject<NodeType>[];
links: LinkObject<NodeType, LinkType>[];
}
type NodeObject<NodeType = {}> = NodeType & {
id?: string | number;
x?: number;
y?: number;
z?: number;
vx?: number;
vy?: number;
vz?: number;
fx?: number;
fy?: number;
fz?: number;
[others: string]: any;
};
type LinkObject<NodeType = {}, LinkType = {}> = LinkType & {
source?: string | number | NodeObject<NodeType>;
target?: string | number | NodeObject<NodeType>;
[others: string]: any;
};
type Accessor<In, Out> = Out | string | ((obj: In) => Out);
type NodeAccessor<NodeType, T> = Accessor<NodeObject<NodeType>, T>;
type LinkAccessor<NodeType, LinkType, T> = Accessor<LinkObject<NodeType, LinkType>, T>;
type TooltipContent = string | React.ReactHTMLElement<HTMLElement>;
type DagMode = 'td' | 'bu' | 'lr' | 'rl' | 'zout' | 'zin' | 'radialout' | 'radialin';
type ForceEngine = 'd3' | 'ngraph';
interface ForceFn<NodeType = {}> {
(alpha: number): void;
initialize?: (nodes: NodeObject<NodeType>[], ...args: any[]) => void;
[key: string]: any;
}
type Coords = { x: number; y: number; z: number; }
type NodePositionUpdateFn = <NodeType = {}>(obj: Object3D, coords: Coords, node: NodeObject<NodeType>) => void | null | boolean;
type LinkPositionUpdateFn = <NodeType = {}, LinkType = {}>(obj: Object3D, coords: { start: Coords, end: Coords }, link: LinkObject<NodeType, LinkType>) => void | null | boolean;
interface ForceGraphProps<
NodeType = {},
LinkType = {}
> extends ConfigOptions {
// Data input
graphData?: GraphData<NodeObject<NodeType>, LinkObject<NodeType, LinkType>>;
nodeId?: string;
linkSource?: string;
linkTarget?: string;
// Container layout
width?: number;
height?: number;
backgroundColor?: string;
showNavInfo?: boolean;
// Node styling
nodeRelSize?: number;
nodeVal?: NodeAccessor<NodeType, number>;
nodeLabel?: NodeAccessor<NodeType, TooltipContent>;
nodeVisibility?: NodeAccessor<NodeType, boolean>;
nodeColor?: NodeAccessor<NodeType, string>;
nodeAutoColorBy?: NodeAccessor<NodeType, string | null>;
nodeOpacity?: number;
nodeResolution?: number;
nodeThreeObject?: NodeAccessor<NodeType, Object3D>;
nodeThreeObjectExtend?: NodeAccessor<NodeType, boolean>;
nodePositionUpdate?: NodePositionUpdateFn | null;
// Link styling
linkLabel?: LinkAccessor<NodeType, LinkType, TooltipContent>;
linkVisibility?: LinkAccessor<NodeType, LinkType, boolean>;
linkColor?: LinkAccessor<NodeType, LinkType, string>;
linkAutoColorBy?: LinkAccessor<NodeType, LinkType, string | null>;
linkWidth?: LinkAccessor<NodeType, LinkType, number>;
linkOpacity?: number;
linkResolution?: number;
linkCurvature?: LinkAccessor<NodeType, LinkType, number>;
linkCurveRotation?: LinkAccessor<NodeType, LinkType, number>;
linkMaterial?: LinkAccessor<NodeType, LinkType, Material | boolean | null>;
linkThreeObject?: LinkAccessor<NodeType, LinkType, Object3D>;
linkThreeObjectExtend?: LinkAccessor<NodeType, LinkType, boolean>;
linkPositionUpdate?: LinkPositionUpdateFn | null;
linkDirectionalArrowLength?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalArrowColor?: LinkAccessor<NodeType, LinkType, string>;
linkDirectionalArrowRelPos?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalArrowResolution?: number;
linkDirectionalParticles?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalParticleSpeed?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalParticleOffset?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalParticleWidth?: LinkAccessor<NodeType, LinkType, number>;
linkDirectionalParticleColor?: LinkAccessor<NodeType, LinkType, string>;
linkDirectionalParticleResolution?: number;
linkDirectionalParticleThreeObject?: LinkAccessor<NodeType, LinkType, Object3D>;
// Force engine (d3-force) configuration
forceEngine?: ForceEngine;
numDimensions?: 1 | 2 | 3;
dagMode?: DagMode;
dagLevelDistance?: number | null;
dagNodeFilter?: (node: NodeObject<NodeType>) => boolean;
onDagError?: ((loopNodeIds: (string | number)[]) => void) | undefined;
d3AlphaMin?: number;
d3AlphaDecay?: number;
d3VelocityDecay?: number;
ngraphPhysics?: object;
warmupTicks?: number;
cooldownTicks?: number;
cooldownTime?: number;
onEngineTick?: () => void;
onEngineStop?: () => void;
// Interaction
onNodeClick?: (node: NodeObject<NodeType>, event: MouseEvent) => void;
onNodeRightClick?: (node: NodeObject<NodeType>, event: MouseEvent) => void;
onNodeHover?: (node: NodeObject<NodeType> | null, previousNode: NodeObject<NodeType> | null) => void;
onNodeDrag?: (node: NodeObject<NodeType>, translate: { x: number, y: number }) => void;
onNodeDragEnd?: (node: NodeObject<NodeType>, translate: { x: number, y: number }) => void;
onLinkClick?: (link: LinkObject<NodeType, LinkType>, event: MouseEvent) => void;
onLinkRightClick?: (link: LinkObject<NodeType, LinkType>, event: MouseEvent) => void;
onLinkHover?: (link: LinkObject<NodeType, LinkType> | null, previousLink: LinkObject<NodeType, LinkType> | null) => void;
linkHoverPrecision?: number;
onBackgroundClick?: (event: MouseEvent) => void;
onBackgroundRightClick?: (event: MouseEvent) => void;
showPointerCursor?: boolean | ((obj: NodeObject<NodeType> | LinkObject<NodeType, LinkType> | undefined) => boolean);
enableNodeDrag?: boolean;
enableNavigationControls?: boolean;
enablePointerInteraction?: boolean;
}
interface ForceGraphMethods<
NodeType = {},
LinkType = {}
> {
// Link styling
emitParticle(link: LinkObject<NodeType, LinkType>): ForceGraph3DInstance;
// Force engine (d3-force) configuration
d3Force(forceName: 'link' | 'charge' | 'center' | string): ForceFn<NodeObject<NodeType>> | undefined;
d3Force(forceName: 'link' | 'charge' | 'center' | string, forceFn: ForceFn<NodeObject<NodeType>> | null): ForceGraph3DInstance;
d3ReheatSimulation(): ForceGraph3DInstance;
// Render control
pauseAnimation(): ForceGraph3DInstance;
resumeAnimation(): ForceGraph3DInstance;
cameraPosition(position: Partial<Coords>, lookAt?: Coords, transitionMs?: number): ForceGraph3DInstance;
zoomToFit(durationMs?: number, padding?: number, nodeFilter?: (node: NodeObject<NodeType>) => boolean): ForceGraph3DInstance;
postProcessingComposer(): EffectComposer;
lights(): Light[];
lights(lights: Light[]): ForceGraph3DInstance;
scene(): Scene;
camera(): Camera;
renderer(): WebGLRenderer;
controls(): object;
refresh(): ForceGraph3DInstance;
// Utility
getGraphBbox(nodeFilter?: (node: NodeObject<NodeType>) => boolean): { x: [number, number], y: [number, number], z: [number, number] };
screen2GraphCoords(x: number, y: number, distance: number): Coords;
graph2ScreenCoords(x: number, y: number, z: number): Coords;
}
type FCwithRef = <NodeType = {}, LinkType = {}>(props: ForceGraphProps<NodeObject<NodeType>, LinkObject<NodeType, LinkType>> & { ref?: React.MutableRefObject<ForceGraphMethods<NodeObject<NodeType>, LinkObject<NodeType, LinkType>> | undefined>; }) => React.ReactElement;
declare const ForceGraph: FCwithRef;
export { ForceGraph as default };
export type { ForceGraphMethods, ForceGraphProps, GraphData, LinkObject, NodeObject };