Skip to content

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.

ts
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.

ts
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.

ts
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

ts
import { Drag, GraphNode, defineGraphConfig } from 'd3-graph-controller'

const config = defineGraphConfig({
  modifiers: {
    drag: (drag: Drag<string, GraphNode>) => {
      // Customize drag behavior
    },
  },
})
ts
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

ts
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

ts
import {
  GraphLink,
  GraphNode,
  GraphSimulation,
  defineGraphConfig,
} from 'd3-graph-controller'

const config = defineGraphConfig({
  modifiers: {
    simulation: (simulation: GraphSimulation<string, GraphNode, GraphLink>) => {
      // Customize simulation
    },
  },
})

Zoom

ts
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.

ts
import { defineGraphConfig } from 'd3-graph-controller'

const config = defineGraphConfig({
  nodeRadius: 32,
})

It is also possible to use a function for dynamic node radii.

ts
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.

ts
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.

ts
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.

ts
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).

ts
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 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.

ts
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].

ts
import { defineGraphConfig } from 'd3-graph-controller'

const config = defineGraphConfig({
  zoom: {
    initial: 1,
    max: 2,
    min: 0.1,
  },
})

Released under the MIT License.