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 PositionInitializer
s 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,
},
})