documentationfor yFiles for HTML 2.6

Using Swimlanes and Partition Grid: Customizing Tabular Layout

The section Layout of Tables and Swimlanes gives an introduction to tabular and swimlane layout, lists the layout styles that support this layout, and explains common usage. You only need to read this section if your use case is not covered by the automatic layout adapter mechanism.

The layout graph model does not contain a specific node type for tables, swimlanes, or similar tabular groups. Instead, the services of the class PartitionGrid can be used to

  • define a grid-like partition consisting of rows and columns,
  • create IDs for the cells of a partition which result from the rows and columns, and
  • assign the nodes of a diagram to these partition cells by means of the cell IDs.

Partitioned layout calculation needs a PartitionGrid object registered via a data provider with the graph using look-up key PARTITION_GRID_DP_KEY and the mapping of the nodes to partition cells registered via data provider with the graph using look-up key PARTITION_CELL_ID_DP_KEY. During layout calculation, an algorithm first retrieves the data providers using the look-up keys, and afterwards retrieves the contained information.

Left-to-right partitioned layout.
partition grid example smaller

Basically, the partition grid needs to be created, and the data providers that hold the necessary information about the partition grid and the mapping of nodes to cells have to be filled manually, and be registered with the graph using the data provider look-up keys defined in class PartitionGrid.

Configuration of a partitioned layout
const graph = getMyGraph()
// Nodes 'n1' and 'n2' to 'n6' (not shown here).
const n1 = getMyNode()

// Create a grid having three rows and four columns.
const grid = new PartitionGrid(3, 4)

// Create an IMapper to store the mapping of nodes to swimlanes, resp. partition
// grid cells.
const cellMap = new Mapper()

// Assign the nodes to the cells.
cellMap.set(n1, grid.createCellId(1, 0))
cellMap.set(n2, grid.createCellId(0, 1))
cellMap.set(n3, grid.createCellId(2, 2))
cellMap.set(n4, grid.createCellId(1, 3))
cellMap.set(n5, grid.createCellId(0, 3))
cellMap.set(n6, grid.createCellId(0, 3))

// Create the layout data for the partition grid and assign the cellMapping and the grid to it.
const partitionGridData = new PartitionGridData({
  grid: grid,
  cellIds: cellMap
})

// Create the supplemental layout data for the hierarchic layout ...
const layoutData = new HierarchicLayoutData({
  // ... and set the layout data for the partition grid accordingly.
  partitionGridData: partitionGridData
})

// Create the layout algorithm...
const hl = new HierarchicLayout()
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
// ... and start layout calculation.
graph.applyLayout(hl, layoutData)
const graph = getMyGraph()
// Nodes 'n1' and 'n2' to 'n6' (not shown here).
const n1 = getMyNode()

// Create a grid having three rows and four columns.
const grid = new PartitionGrid(3, 4)

// Create an IMapper to store the mapping of nodes to swimlanes, resp. partition
// grid cells.
const cellMap = new Mapper<INode, PartitionCellId>()

// Assign the nodes to the cells.
cellMap.set(n1, grid.createCellId(1, 0))
cellMap.set(n2, grid.createCellId(0, 1))
cellMap.set(n3, grid.createCellId(2, 2))
cellMap.set(n4, grid.createCellId(1, 3))
cellMap.set(n5, grid.createCellId(0, 3))
cellMap.set(n6, grid.createCellId(0, 3))

// Create the layout data for the partition grid and assign the cellMapping and the grid to it.
const partitionGridData = new PartitionGridData({
  grid: grid,
  cellIds: cellMap
})

// Create the supplemental layout data for the hierarchic layout ...
const layoutData = new HierarchicLayoutData({
  // ... and set the layout data for the partition grid accordingly.
  partitionGridData: partitionGridData
})

// Create the layout algorithm...
const hl = new HierarchicLayout()
hl.layoutOrientation = LayoutOrientation.LEFT_TO_RIGHT
// ... and start layout calculation.
graph.applyLayout(hl, layoutData)

Configuration of a partitioned layout shows the basic setup of the partition grid seen in Left-to-right partitioned layout.. Observe how the layout algorithm respects the specified organization of the nodes within the partition cells.

To create IDs for the cells of a partition (single cells and ranges of cells), class PartitionGrid provides the methods below. The IDs can be used to assign the nodes of a diagram to partition cells. Nodes that do not have an ID associated, can be placed in any partition cell by a layout algorithm.

createCellId(rowIndex: number, columnIndex: number): PartitionCellId
Creates a partition ID for single cells.
createCellSpanId(fromRowIndex: number, fromColIndex: number, toRowIndex: number, toColIndex: number): PartitionCellId
Creates a partition ID that represent a (two-dimensional) range of cells stretching the specified rows and columns.

In the set of all specified cells of a partition (single cells and ranges of cells), no two ranges of cells are allowed to overlap with each other, or overlap with a single cell, i.e., the set needs to be disjoint. In particular, this also means that no partition cell can have more than one partition ID associated with it.

Reordering rows and columns

Class PartitionGrid enables further optimization of the layout outcome when there are no cell spans specified in a partition grid. The following properties can be used to control whether the order of rows and columns in a swimlane/partitioned layout shall be automatically determined.

optimizeRowOrder: boolean
Optimize the order of rows to minimize the diagram’s overall edge lengths.
optimizeColumnOrder: boolean
Optimize the order of columns to minimize the diagram’s overall edge lengths.