Force-directed graph visualization library.
npm install @logixode/force-graph-libA TypeScript library for creating interactive force-directed graphs with advanced features and optimizations for handling large datasets.
- Features
- Installation
- Usage in TypeScript
- Usage in Vue.js
- Detail for Types
- API Reference
- License
- ๐จ Highly customizable styling for nodes, links, and groups.
- ๐ฏ Dynamic label visibility control based on zoom level.
- ๐ Incremental data loading and dynamic data updates.
- โ๏ธ Fine-grained control over the force simulation (e.g., collision, clustering).
- ๐ Optimized for large datasets with features like dynamic cooldown time.
- ๐ผ๏ธ Group visualization with borders and labels.
- ๐ Zoom and pan, including programmatic focus on specific nodes or coordinates.
- โ Persist node positions after dragging.
- ๐ง Responsive design that adapts to container size changes.
- ๐ง Methods to query and manipulate graph data and state.
- ๐งน Full cleanup and resource destruction.
``bash`
npm install @logixode/force-graph-lib
Here's an example of how to use the library in a TypeScript project.
HTML File
`html`
TypeScript File (main.ts)
`typescript
import { ForceGraph } from '@logixode/force-graph-lib'
import type { GraphData, GraphOptions, NodeData } from '@logixode/force-graph-lib'
// 1. Get the container element
const container = document.getElementById('graph-container') as HTMLElement
// 2. Define initial data
const initialData: GraphData = {
nodes: [
{ id: '1', label: 'Topic Node', type: 'topic' },
{ id: '2', label: 'Post A', type: 'post' },
{ id: '3', label: 'Post B', type: 'post' },
],
links: [
{ source: '1', target: '2' },
{ source: '1', target: '3' },
],
}
// 3. Define graph options
const options: GraphOptions = {
width: container.clientWidth,
height: container.clientHeight,
keepDragPosition: true,
labelThreshold: 1.2,
// Node styling
nodeSize: (node: NodeData) => (node.type === 'topic' ? 5 : 2),
nodeLabel: (node: NodeData) => node.label as string,
nodeColor: (node: NodeData) => (node.type === 'topic' ? '#FA8F21' : '#1877F2'),
nodeBorderWidth: 0.5,
nodeBorderColor: 'white',
// Link styling
linkWidth: 0.4,
linkCurvature: 0.1,
// Simulation forces
collide: (node: NodeData) => (node.type === 'topic' ? 15 : 5),
cluster: (node: NodeData) => node.type, // Group nodes by their 'type'
}
// 4. Initialize the graph
const graph = new ForceGraph(container, initialData, options)
// 5. Interact with the graph
setTimeout(() => {
const newData = {
nodes: [
{ id: '4', label: 'Post C', type: 'post' },
{ id: '5', label: 'Repost', type: 'repost' },
],
links: [
{ source: '2', target: '4' },
{ source: '1', target: '5' },
],
}
graph.addData(newData)
graph.focusPosition({ id: '4' })
}, 2000)
// Handle window resizing
window.addEventListener('resize', () => {
graph.setOptions({
width: container.clientWidth,
height: container.clientHeight,
})
graph.reinitialize()
})
`
Here is a basic example of integrating the library within a Vue 3 component using the Composition API.
`vue
`
`typescript`
interface GraphData {
nodes: Array<{
id: string | number
[key: string]: any
}>
links: Array<{
source: string | number
target: string | number
[key: string]: any
}>
}
`typescript
interface GraphOptions {
width?: number
height?: number
labelThreshold?: number
keepDragPosition?: boolean
// Node Styling
nodeSize?: number | ((node: NodeData) => number)
nodeLabel?: string | ((node: NodeData) => string)
nodeLabelColor?: string | ((node: NodeData) => string)
nodeColor?: string | ((node: NodeData) => string)
nodeBorderColor?: string | ((node: NodeData) => string)
nodeBorderWidth?: number | ((node: NodeData) => number)
// Link Styling
linkWidth?: number | ((link: LinkData) => number)
linkCurvature?: number | 'curvature' | ((link: LinkData) => number)
linkDirectionalParticles?: number | ((link: LinkData) => number)
linkDirectionalParticleSpeed?: number | ((link: LinkData) => number)
linkDirectionalParticleWidth?: number | ((link: LinkData) => number)
linkDirectionalParticleColor?: string | ((link: LinkData) => string)
// Simulation
cluster?: (node: NodeData) => any
collide?: (node: NodeData) => number
// Grouping
showGroups?: boolean
groupBy?: string | ((node: NodeData) => string | undefined)
groupBorderColor?: string | ((groupId: string) => string)
groupBorderWidth?: number
groupBorderOpacity?: number
groupLabelColor?: string | ((groupId: string) => string)
groupLabelSize?: number
groupLabelThreshold?: number
groupPadding?: number
}
`
`typescript`
new ForceGraph(container: HTMLElement, data: GraphData, options?: GraphOptions)
#### Data Management
- addData(newData: GraphData): Promise: Asynchronously adds new nodes and links, avoiding duplicates.updateData(data: GraphData): void
- : Merges new data with existing data. (Prefer addData for incremental updates).graphData(data: GraphData): ForceGraph
- : Replaces the entire graph data and re-renders.updateNode(id: string | number, updates: Partial
- : Updates properties of a single node.removeNode(id: string | number): boolean
- : Removes a node and its associated links.reset()
- : Clears all graph data and re-initializes the component.
#### Getters
- getData(): GraphData: Returns the current graph data object.getNodesData(): NodeData[]
- : Returns an array of all nodes.getLinksData(): LinkData[]
- : Returns an array of all links.getNodeById(id: string | number): NodeData | undefined
- : Finds a node by its ID.hasNode(id: string | number): boolean
- : Checks if a node exists.getDataSize(): { nodes: number; links: number }
- : Returns the number of nodes and links.getOptions(): GraphOptions
- : Returns the current options object.
#### Rendering & Options
- setOptions(options: Partial: Updates one or more options without re-initializing the entire graph.setLabelThreshold(threshold: number)
- : Sets the zoom level at which node labels become visible.refreshGraph()
- : Refreshes the graph with the current data. Useful after manual data manipulation.reinitialize()
- : Performs a complete re-initialization. Use when major changes like dimensions are needed.applyOptions()
- : Re-applies all current options to the graph.
#### Camera & View
- focusPosition(position: { id?: string; x?: number; y?: number }): void: Centers the view on a specific node or coordinate.
#### Grouping
- showGroups(show: boolean): ForceGraph: Enables or disables the group visualization.setGroupBy(groupBy: string | ((node: NodeData) => string | undefined)): ForceGraph
- : Sets the property or function used to group nodes.setGroupOptions(options: object): ForceGraph
- : Sets styling options for groups (e.g., borderColor, padding).getGroups(): string[]
- : Returns an array of all unique group IDs.getNodesInGroup(groupId: string): NodeData[]
- : Returns all nodes belonging to a specific group.
#### Lifecycle
- destroy()`: Cleans up all resources, including the simulation and event listeners. Essential for single-page applications.
MIT