C

SeriesParallelLayoutData<TNode, TEdge, TNodeLabel, TEdgeLabel>

Specifies custom data for the SeriesParallelLayout.
Inheritance Hierarchy

Members

Show:

Constructors

Parameters

Properties

Gets or sets the ChildOrderData<TNode, TEdge> which specifies how child nodes are to be sorted.
For general graphs, the child orders are only used for the series-parallel part of the graph. Non-series-parallel edges are not included and will be routed by the edge router for non-series-parallel edges .
The order cannot be maintained in all cases because the target nodes may not be completely independent.
final

Examples

The ChildOrderData<TNode, TEdge> class provides two primary methods for determining the order of a parent's child nodes: either by directly sorting the child nodes using targetNodeComparators or targetNodeComparables, or by sorting the outgoing edges from the parent node to its child nodes using outEdgeComparators or outEdgeComparables. Setting a comparable value (e.g. a number or a string) for all nodes means that the child nodes of all parents in the graph are ordered using those values.

Using a comparable to order by the height of the child nodes.
// Use the node height as comparable to sort the child nodes by their height
layoutData.childOrder.targetNodeComparables = (child) =>
  child.layout.height

Using a comparison delegate for specific nodes is convenient if the child nodes should be ordered only for particular parent nodes.

Ordering child nodes only for a specific parent node and using the child's tag.
layoutData.childOrder.targetNodeComparators = (parent: INode) => {
  if (parent == specificNode) {
    // Define a comparison function only for a specific parent node
    // ... and sort its child nodes based on an order value specified in their tags
    return (child1: INode, child2: INode) =>
      child1.tag.sequenceOrder.compareTo(child2.tag.sequenceOrder)
  }

  // No ordering for the edges around the other nodes
  return null
}

Setting a comparable value (e.g. a number or a string) for all edges means that the outgoing edges of all parents in the graph are ordered using those values.

Using a comparable to order by the label count of the edges.
// Use the label count of the out edges as comparable value to sort them
layoutData.childOrder.outEdgeComparables = (edge) => edge.labels.size

Using a comparison delegate for specific edges is convenient if the outgoing edges should be ordered only for particular nodes.

Ordering edges only for a specific node and using the edge's tag.
layoutData.childOrder.outEdgeComparators = (parent: INode) => {
  if (parent == specificNode) {
    // Define a comparison function only for a specific parent node
    // ... and sort its outgoing edges based on an order value specified in their tags
    return (edge1: IEdge, edge2: IEdge) =>
      edge1.tag.sequenceOrder.compareTo(edge2.tag.sequenceOrder)
  }

  // No ordering for the edges around the other nodes
  return null
}

See Also

Developer's Guide
API
OUT_EDGE_COMPARATOR_DATA_KEY
Gets or sets the mapping from edges to their SeriesParallelLayoutEdgeDescriptor.
Gets or sets the mapping that provides an EdgeLabelPreferredPlacement instance for edge labels.
conversionfinal

Examples

Depending on how much customization is needed, some ways of setting EdgeLabelPreferredPlacements are more convenient than others. For example, to set the same descriptor for all labels, you can just use the constant property:

Setting the same EdgeLabelPreferredPlacement for all labels
layoutData.edgeLabelPreferredPlacements = new EdgeLabelPreferredPlacement(
  {
    // Place labels along the edge
    angleReference: LabelAngleReferences.RELATIVE_TO_EDGE_FLOW,
    angle: 0,
    // ... on either side
    edgeSide: LabelEdgeSides.LEFT_OF_EDGE | LabelEdgeSides.RIGHT_OF_EDGE,
    // ... with a bit of distance to the edge
    distanceToEdge: 5,
  },
)

If some labels should use custom placement or this has to be configured ahead of time, you can use the mapper instead:

Customizing the placement of certain labels individually via a mapper
// Place label1 orthogonal to the edge anywhere on it
layoutData.edgeLabelPreferredPlacements.mapper.set(
  label1,
  new EdgeLabelPreferredPlacement({
    placementAlongEdge: LabelAlongEdgePlacements.ANYWHERE,
    angleReference: LabelAngleReferences.RELATIVE_TO_EDGE_FLOW,
    angle: Math.PI / 2,
  }),
)
// Place label2 near the edge's source on either side of it, and make it parallel to the edge
layoutData.edgeLabelPreferredPlacements.mapper.set(
  label2,
  new EdgeLabelPreferredPlacement({
    placementAlongEdge: LabelAlongEdgePlacements.AT_SOURCE,
    edgeSide: LabelEdgeSides.RIGHT_OF_EDGE | LabelEdgeSides.LEFT_OF_EDGE,
    angleReference: LabelAngleReferences.RELATIVE_TO_EDGE_FLOW,
    angle: 0,
  }),
)

When the preferred placement can be inferred from the label itself, a delegate is usually the easiest choice:

Configuring preferred placement for all labels with a delegate
layoutData.edgeLabelPreferredPlacements = (
  label: ILabel,
): EdgeLabelPreferredPlacement => {
  const customData = label.tag as CustomData
  return new EdgeLabelPreferredPlacement({
    angle: 0,
    angleReference: LabelAngleReferences.RELATIVE_TO_EDGE_FLOW,
    // If the tag says to place the label in the center, put it in the center parallel to the edge's path
    // All other labels can be placed anywhere, but on the side of the edge.
    placementAlongEdge: customData.placeInCenter
      ? LabelAlongEdgePlacements.AT_CENTER
      : LabelAlongEdgePlacements.ANYWHERE,
    edgeSide: customData.placeInCenter
      ? LabelEdgeSides.ON_EDGE
      : LabelEdgeSides.LEFT_OF_EDGE | LabelEdgeSides.RIGHT_OF_EDGE,
  })
}

Note that the preferred placement can also be inferred from an arbitrary ILabelModelParameter:

Configuring preferred placement from a label model parameter
layoutData.edgeLabelPreferredPlacements =
  EdgeLabelPreferredPlacement.fromParameter(
    NinePositionsEdgeLabelModel.CENTER_CENTERED,
  )

See Also

API
EdgeLabelPreferredPlacement, EDGE_LABEL_PREFERRED_PLACEMENT_DATA_KEY
Gets or sets the mapping from nodes to their ISeriesParallelLayoutPortAssigner.
If there is no ISeriesParallelLayoutPortAssigner specified for a node, the layout algorithm uses the default assigner.
conversionfinal

See Also

Developer's Guide
API
PORT_ASSIGNER_DATA_KEY
Gets or sets the sub-data that influences the placement of the ports.

The port placement can be influenced by specifying EdgePortCandidates for the source and target of an edge, as well as by specifying NodePortCandidates at the nodes.

In addition, it is possible to specify that ports should be grouped at the source or target.

If both EdgePortCandidates and NodePortCandidates are specified, the layout algorithm tries to match them. An edge port candidate matches a node port candidate if

  • Their matchingIds are equal or one type is null,
  • They belong to a common side or one side is ANY, and
  • If both candidates are fixed, they describe the same positions.

The position of a port candidate is defined by offset or the actual offset of the edge endpoint for fixed-from-sketch candidates. When there is no match, the port candidate with the lowest costs specified for the edge is chosen.

The portAssigners specified for the individual nodes may ignore the specified port placement constraints. Additionally, support for port placement constraints through additional pre- and postprocessing is provided by the PortPlacementStage, which is added to the layoutStages and enabled by default.
final
Gets or sets a mapping from edges to an object representing their source edge group.
Edges sharing a source group identifier will share a common bus near the source or at a common source node if possible.
conversionfinal

See Also

API
SOURCE_EDGE_GROUP_ID_DATA_KEY
Gets or sets a mapping from edges to an object representing their target edge group.
Edges sharing a target group identifier will share a common bus near the target or at a common target node if possible.
conversionfinal

See Also

API
TARGET_EDGE_GROUP_ID_DATA_KEY

Methods

Combines this instance with the given layout data.
This keeps the current instance unmodified and instead returns a new instance that dynamically combines the contents of all involved instances.
final

Parameters

data: LayoutData<TNode, TEdge, TNodeLabel, TEdgeLabel>
The LayoutData<TNode, TEdge, TNodeLabel, TEdgeLabel> to combine this instance with.

Return Value

LayoutData<TNode, TEdge, TNodeLabel, TEdgeLabel>
The combined layout data.

See Also

Developer's Guide
API
CompositeLayoutData, GenericLayoutData