Configuration
Both behavior and visuals of graphs can be customized by passing additional parameters to defineGraphConfig().
Callbacks
nodeClicked
The nodeClicked callback is called whenever a node is double-clicked (using the primary mouse button) or double-tapped in a short time. If set, the default behavior of focusing a node is disabled.
import { GraphNode, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
callbacks: {
nodeClicked: (node: GraphNode) => console.log(node.id),
},
})Initial Settings
The GraphController settings that can be changed after initialization can have their initial values configured. The reference below shows the default configuration.
linkFilter receives a link as its parameter.
nodeTypeFilter is an array of type tokens. Only nodes whose type is included in the array will be shown. If omitted, the graph will include all nodes.
import { defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
initial: {
includeUnlinked: true,
linkFilter: () => true,
nodeTypeFilter: undefined,
showLinkLabels: true,
showNodeLabels: true,
},
})Markers
Markers are displayed at the end of links. Because precise marker dimensions are required for path calculations, it is necessary to provide a lot of data. Hence, it is recommended to only use the default marker Markers.Arrow with customizable size as seen below.
import { Markers, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
marker: Markers.Arrow(4),
})Modifiers
If absolute control is required, modifiers can be used to customize D3 internals.
TIP
Configuring modifiers is usually not required. Do not forget to unset predefined callbacks like pointerdown and contextmenu for node if required.
Drag
import { Drag, GraphNode, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
modifiers: {
drag: (drag: Drag<string, GraphNode>) => {
// Customize drag behavior
},
},
})Links
import { GraphLink, defineGraphConfig } from 'd3-graph-controller'
import type { Selection } from 'd3-selection'
const config = defineGraphConfig({
modifiers: {
link: (
selection: Selection<SVGPathElement, GraphLink, SVGGElement, undefined>,
) => {
// Customize link paths
},
linkLabel: (
selection: Selection<SVGTextElement, GraphLink, SVGGElement, undefined>,
) => {
// Customize link labels
},
},
})Nodes
import { GraphNode, defineGraphConfig } from 'd3-graph-controller'
import type { Selection } from 'd3-selection'
const config = defineGraphConfig({
modifiers: {
node: (
selection: Selection<SVGCircleElement, GraphNode, SVGGElement, undefined>,
) => {
// Customize node circles
},
nodeLabel: (
selection: Selection<SVGTextElement, GraphNode, SVGGElement, undefined>,
) => {
// Customize node labels
},
},
})Simulation
import {
GraphLink,
GraphNode,
GraphSimulation,
defineGraphConfig,
} from 'd3-graph-controller'
const config = defineGraphConfig({
modifiers: {
simulation: (simulation: GraphSimulation<string, GraphNode, GraphLink>) => {
// Customize simulation
},
},
})Zoom
import { Zoom, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
modifiers: {
zoom: (zoom: Zoom) => {
// Customize zoom
},
},
})Node Radius
The radius of nodes is used for their visualization as well as the underlying simulation. It can be configured using the nodeRadius property of the config.
import { defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
nodeRadius: 32,
})It is also possible to use a function for dynamic node radii.
import { GraphNode, defineGraphConfig } from 'd3-graph-controller'
type CustomNode = GraphNode & { radius: number }
const config = defineGraphConfig<string, CustomNode>({
nodeRadius: (node: CustomNode) => node.radius,
})Position Initialization
When a GraphController is created, it initializes the positions of nodes that do not have their coordinates set. The behavior of this initialization can be customized by providing a PositionInitializer. A PositionInitializer is a function that receives a GraphNode as well as the width and height of a graph and returns two coordinates. This library provides two PositionInitializers out of the box.
By default, PositionInitializers.Centered is used. Alternatively, PositionInitializers.Randomized or custom implementations can be used.
import { PositionInitializers, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
positionInitializer: PositionInitializers.Randomized,
})Resizing
Graphs can be resized to fit their container. This can either happen manually by calling a GraphController's resize method or automatically by setting autoResize to true.
import { defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
autoResize: true,
})Simulation
The interactivity of the graph is driven by a d3 simulation. Its forces and behavior can be configured for precise control.
Alphas
Alpha values determine the heat or activity of a simulation. The higher the value, the stronger the simulation will react. After certain actions, the simulations needs to be restarted. The alpha values for those restarts can be configured. Reference the default configuration below for the available options.
import { GraphNode, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
simulation: {
alphas: {
drag: {
end: 0,
start: 0.1,
},
filter: {
link: 1,
type: 0.1,
unlinked: {
include: 0.1,
exclude: 0.1,
},
},
focus: {
acquire: (node: GraphNode) => 0.1,
release: (node: GraphNode) => 0.1,
},
initialize: 1,
labels: {
links: {
hide: 0,
show: 0,
},
nodes: {
hide: 0,
show: 0,
},
},
resize: 0.5,
},
},
})TIP
simulation.alphas.focus.acquire and simulation.alphas.focus.release receive the (un-)focused node as a parameter. simulation.alphas.resize can either be a static number or a function receiving a ResizeContext as its parameter.
Forces
Forces can be customized or disabled as required. Some forces provide additional customizability. Reference the configuration below, which matches the default values.
TIP
Settings simulation.forces.collision.radiusMultiplier to a higher value can drastically reduce the number of intersecting edges.
All strength properties can also be functions that receive the subject of the force as a parameter for individual strength. Except forces.link, the subject is always a GraphNode (or the custom type used).
import { GraphLink, defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
simulation: {
forces: {
centering: {
enabled: true,
strength: 0.1,
},
charge: {
enabled: true,
strength: -1,
},
collision: {
enabled: true,
strength: 1,
radiusMultiplier: 2,
},
link: {
enabled: true,
length: (link: GraphLink) => 128,
strength: 1,
},
},
},
})Link Length
Link length is used to determine the length of links for the simulation. Similar to node radii, link length can be configured on a per-link basis. Once again, custom link types can be used to provide the required data.
import { GraphLink, GraphNode, defineGraphConfig } from 'd3-graph-controller'
type CustomLink = GraphLink & { length: number }
const config = defineGraphConfig<string, GraphNode, CustomLink>({
simulation: {
forces: {
link: {
length: (link: CustomLink) => link.length,
},
},
},
})Zoom
For the zooming functionality, the initial value as well as its boundaries can be configured as seen below.
WARNING
Currently, there's no validation of the values. The min value must be larger than 0 and the initial value must be withing the range [min, max].
import { defineGraphConfig } from 'd3-graph-controller'
const config = defineGraphConfig({
zoom: {
initial: 1,
max: 2,
min: 0.1,
},
})