documentationfor yFiles for HTML 2.6

AdjacencyGraphBuilder

Populates a graph from custom data where node data items know about their predecessors and/or successors.

Inheritance Hierarchy
AdjacencyGraphBuilder

Remarks

This class can be used when the data consists of one or more collections of nodes, each of which knows its neighbors, and optionally, groups. The methods createNodesSource, createGroupNodesSource, createSuccessorsSource, createPredecessorsSource, createOutEdgesSource, and createInEdgesSource create new source collections from which nodes and group nodes will be created.

Generally, using the AdjacencyGraphBuilder class consists of a few basic steps:

  1. Create an AdjacencyGraphBuilder and optionally, provide an IGraph on which it should operate.
    const adjacencyBuilder = new AdjacencyGraphBuilder(graph)
  2. Create one or more nodes sources from which the AdjacencyGraphBuilder creates the initial nodes in the graph. By adding group node sources, group nodes ar created.
    const orangeData = getAdjacencyNodesData()
    // create source for initial nodes (orange nodes)
    const orangeNodesSource = adjacencyBuilder.createNodesSource(
      orangeData, // nodes data
      // nodes data
      (orangeDataItem) => orangeDataItem.nodeId
    ) // node id provider
  3. To create neighbor nodes and edges to or from them, create new successor sources or predecessor sources as neighbor sources of the initial sources.

    By adding existing successor sources or predecessor sources, edges can be defined between existing sources.

    // create an EdgeCreator for edges adjacent to orange nodes
    const orangeEdgeCreator = new EdgeCreator()
    // create a nodes source for the green nodes as successor of orangeNodesSource
    const greenNodesSource = orangeNodesSource.createSuccessorsSource(
      (orangeNodeDataItem) => orangeNodeDataItem.successorNodes,
      orangeEdgeCreator
    )
    // add the same source also as predecessor
    orangeNodesSource.addPredecessorsSource(
      (orangeNodeDataItem) => orangeNodeDataItem.predecessorNodes,
      greenNodesSource,
      orangeEdgeCreator
    )// create an EdgeCreator for edges adjacent to orange nodes
    const orangeEdgeCreator = new EdgeCreator<OrangeData>()
    // create a nodes source for the green nodes as successor of orangeNodesSource
    const greenNodesSource = orangeNodesSource.createSuccessorsSource(
      (orangeNodeDataItem) => orangeNodeDataItem.successorNodes,
      orangeEdgeCreator
    )
    // add the same source also as predecessor
    orangeNodesSource.addPredecessorsSource(
      (orangeNodeDataItem) => orangeNodeDataItem.predecessorNodes,
      greenNodesSource,
      orangeEdgeCreator
    )

    By adding existing successor ids or predecessor ids, edges can be defined between the nodes of existing sources where the neighbors are defined by their id.

    const greenEdgeCreator = new EdgeCreator()
    // register EdgeCreator for edges to orange successor nodes created by orangeNodesSource
    greenNodesSource.addSuccessorIds(
      (greenNodeDataItem) => greenNodeDataItem.successorNodeIds,
      greenEdgeCreator
    )
    // register EdgeCreator for edges to orange predecessor nodes created by orangeNodesSource
    greenNodesSource.addPredecessorIds(
      (greenNodeDataItem) => greenNodeDataItem.predecessorNodeIds,
      greenEdgeCreator
    )const greenEdgeCreator = new EdgeCreator<GreenData>()
    // register EdgeCreator for edges to orange successor nodes created by orangeNodesSource
    greenNodesSource.addSuccessorIds(
      (greenNodeDataItem) => greenNodeDataItem.successorNodeIds,
      greenEdgeCreator
    )
    // register EdgeCreator for edges to orange predecessor nodes created by orangeNodesSource
    greenNodesSource.addPredecessorIds(
      (greenNodeDataItem) => greenNodeDataItem.predecessorNodeIds,
      greenEdgeCreator
    )

    Using the methods mentioned above, edges are always created implicitly between the nodes of an AdjacencyNodesSource<TDataItem> and their added neighbors providing the data items of the nodes to the EdgeCreator<TDataItem>.

    When the data items of an AdjacencyNodesSource<TDataItem> do not know their neighbor items directly but know their outgoing and incoming edges which in turn know the data items of the opposite nodes, the corresponding methods createOutEdgesSource, createInEdgesSource, addOutEdgesSource, addInEdgesSource, addOutEdgesSourceToId, and addInEdgesSourceToId can be used that provide the specified edge data items to the EdgeCreator<TDataItem>.

    // create and register EdgeCreator for purple edges
    const purpleEdgeCreator = new EdgeCreator()
    orangeNodesSource.addOutEdgesSource(
      (nodeDataItem) => nodeDataItem.purpleOutEdges,
      (purpleEdgeDataItem) => purpleEdgeDataItem.greenTargetNode,
      greenNodesSource,
      // use existing nodesSource for target nodes
      purpleEdgeCreator
    )
    // create and register EdgeCreator for yellow edges
    orangeNodesSource.addOutEdgesSourceToId(
      (orangeNodeDataItem) => orangeNodeDataItem.yellowOutEdges,
      (yellowEdgeDataItem) => yellowEdgeDataItem.targetNodeId,
      new EdgeCreator()
    )// create and register EdgeCreator for purple edges
    const purpleEdgeCreator = new EdgeCreator<PurpleEdgeData>()
    orangeNodesSource.addOutEdgesSource<PurpleEdgeData, GreenData>(
      (nodeDataItem) => nodeDataItem.purpleOutEdges,
      (purpleEdgeDataItem) => purpleEdgeDataItem.greenTargetNode,
      greenNodesSource, // use existing nodesSource for target nodes
      purpleEdgeCreator
    )
    // create and register EdgeCreator for yellow edges
    orangeNodesSource.addOutEdgesSourceToId<YellowEdgeData>(
      (orangeNodeDataItem) => orangeNodeDataItem.yellowOutEdges,
      (yellowEdgeDataItem) => yellowEdgeDataItem.targetNodeId,
      new EdgeCreator()
    )
  4. Each AdjacencyNodesSource<TDataItem> provides a NodeCreator<TDataItem> that allows for further specification of how the items from this source should be created. You can provide defaults for the default styling but also bind more specific styling based on the actual data item with the styleProvider and styleBindings.
    orangeNodesSource.nodeCreator.defaults.shareStyleInstance = false
    orangeNodesSource.nodeCreator.defaults.style = new ShapeNodeStyle({
      stroke: 'darkRed',
      fill: 'orange'
    })
    // nodes without successor should have a diamond shape
    orangeNodesSource.nodeCreator.styleBindings.addBinding(
      'shape',
      (redDataItem) =>
        redDataItem.successorNodes.length > 0 ? 'roundRectangle' : 'diamond'
    )

    It also allows for obtaining layout information from the data item (layoutProvider), as well as further specification of the created node's tag (tagProvider).

  5. The edge creation can be adjusted by passing suitable EdgeCreator<TDataItem> instances when adding a neighbor source. It allows to specify the styling of the created edges (defaults, styleProvider, styleBindings).
    greenEdgeCreator.defaults.style = new PolylineEdgeStyle({
      stroke: 'forestGreen'
    })

    Furthermore, it allows for obtaining bend locations from the data item (bendsProvider), as well as further specification of the created edge's tag (tagProvider).

    greenEdgeCreator.bendsProvider = (edgeDataItem) => edgeDataItem.bendPoints
  6. Optionally, labels can be added by providing one or multiple label bindings. If there is a varying number of labels per node, createLabelsSource can be used, instead. Similar methods are also available on the EdgeCreator<TDataItem>.

    The LabelsSource<TDataItem> provides a LabelCreator<TDataItem> that allows for adjusting all aspects of the label creation, like style, text, size, and tag.

    const edgeLabelCreator = purpleEdgeCreator.createLabelBinding(
      (purpleEdgeData) => purpleEdgeData.connectionType
    )
    edgeLabelCreator.defaults.style = new DefaultLabelStyle({
      backgroundFill: 'white',
      backgroundStroke: 'purple',
      textSize: 8
    })
  7. Call buildGraph to populate the graph. You can apply a layout algorithm afterward to make the graph look nice.
    // Build a graph initially
    adjacencyBuilder.buildGraph()
    // Apply a layout in a subsequent step
    graph.applyLayout(new HierarchicLayout())
  8. If your items or collections change later, call updateGraph to make the changes visible in the graph. If the data item instances have changed, you can call setData.
    // Set the new data collections:
    adjacencyBuilder.setData(orangeNodesSource, getAdjacencyNodesData())
    // Update a graph after the business data has changed
    adjacencyBuilder.updateGraph()
    // Apply a layout in a subsequent step
    graph.applyLayout(new HierarchicLayout())

You can further customize how nodes, groups, and edges are created by adding event handlers to the various events and modifying the items there. This can be used to modify items in ways that are not directly supported by the available bindings or defaults. There are creation and update events for all items, which allow for separate customization when nodes, groups, and edges are created or updated. For completely static graphs, where updateGraph is not needed, the update events can be safely ignored.

Related Reading in the Developer's Guide

The different graph builders are discussed in the section Creating a Graph from Business Data. Class AdjacencyGraphBuilder, in particular, is topic of section AdjacencyGraphBuilder.

Type Details

yfiles module
view-component
yfiles-umd modules
All view modules
Legacy UMD name
yfiles.binding.AdjacencyGraphBuilder

See Also

This class serves as a convenient way to create graphs. Some aspects to look out for:

If you need to extensively modify your data in order to fit the requirements of the AdjacencyGraphBuilder, it is often better to write the code interfacing with the graph by hand instead of relying on AdjacencyGraphBuilder.

updateGraph merely updates the graph structure. Any other bound data must be updated explicitly if necessary. Calling the respective update methods on the creators (e.g. updateStyle), resolves the provider (e.g. styleProvider) and applies the bindings (e.g. applyStyleBindings). The latter can also be applied solely.

For example, to update any aspect of node creation:
// configure the NodeCreator to update non-structural aspects
nodesSource.nodeCreator.addNodeUpdatedListener((sender, evt) => {
  nodesSource.nodeCreator.updateLayout(evt.graph, evt.item, evt.dataItem)
  nodesSource.nodeCreator.updateStyle(evt.graph, evt.item, evt.dataItem)
  nodesSource.nodeCreator.updateTag(evt.graph, evt.item, evt.dataItem)
  nodesSource.nodeCreator.updateLabels(evt.graph, evt.item, evt.dataItem)
})

builder.updateGraph()

Constructors

Properties

Methods

Events