Specifies custom data for the BalloonLayout.
Examples
The following example shows how to create a new instance of BalloonLayoutData and use it with an BalloonLayout:
const layoutData = new BalloonLayoutData()
// Use the node whose label says "Root" as root node for the tree
layoutData.treeRoot = (node) => node.labels.get(0).text === 'Root'
// Place children of nodes with many children interleaved
layoutData.interleavedNodes = (node) =>
graphComponent.graph.outDegree(node) > 5
graphComponent.graph.applyLayout(new BalloonLayout(), layoutData)
const layoutData = new BalloonLayoutData()
// Use the node whose label says "Root" as root node for the tree
layoutData.treeRoot = (node: INode): boolean =>
node.labels.get(0).text === 'Root'
// Place children of nodes with many children interleaved
layoutData.interleavedNodes = (node: INode) =>
graphComponent.graph.outDegree(node) > 5
graphComponent.graph.applyLayout(new BalloonLayout(), layoutData)
In many cases the complete initialization of BalloonLayoutData can also be done in a single object initializer:
const layoutData = new BalloonLayoutData({
// Use the node whose label says "Root" as root node for the tree
treeRoot: (node) => node.labels.get(0).text === 'Root',
// Place children of nodes with many children interleaved
interleavedNodes: (node) => graphComponent.graph.outDegree(node) > 5
})
graphComponent.graph.applyLayout(new BalloonLayout(), layoutData)
const layoutData = new BalloonLayoutData({
// Use the node whose label says "Root" as root node for the tree
treeRoot: (node: INode): boolean => node.labels.get(0).text === 'Root',
// Place children of nodes with many children interleaved
interleavedNodes: (node: INode): boolean =>
graphComponent.graph.outDegree(node) > 5
})
graphComponent.graph.applyLayout(new BalloonLayout(), layoutData)
Type Details
- yfiles module
- view-layout-bridge
- yfiles-umd modules
- view-layout-bridge
- Legacy UMD name
- yfiles.tree.BalloonLayoutData
See Also
Constructors
Creates a new instance of BalloonLayoutData which helps configuring BalloonLayout.
Parameters
A map of options to pass to the method.
- interleavedNodes - ItemCollection<INode>
The collection of nodes whose children should be arranged in an interleaved fashion. This option sets the interleavedNodes property on the created object.
- nodeHalos - ItemMapping<INode,NodeHalo>
- abortHandler - AbortHandler
The AbortHandler used during the layout. This option sets the abortHandler property on the created object.
- treeRoot - SingleItem<INode>
The mapping for marking the node that will be used as root node of the tree. This option sets the treeRoot property on the created object.
- edgeLabelPreferredPlacement - ItemMapping<ILabel,PreferredPlacementDescriptor>
The mapping that provides a PreferredPlacementDescriptor instance for edge ILabels. This option sets the edgeLabelPreferredPlacement property on the created object.
- outEdgeComparer - function(IEdge, IEdge):number
The comparison function used to sort the nodes' outgoing edges. This option sets the outEdgeComparer property on the created object.
- nodeTypes - ItemMapping<INode,Object>
The mapping from nodes to an object defining the node type, which influences the ordering of child nodes such that those with same type are preferably placed next to each other. This option sets the nodeTypes property on the created object.
Properties
Gets or sets the AbortHandler used during the layout.
Remarks
An AbortHandler can be used to gracefully stop or cancel a running layout and offers options for automatically doing so after a predetermined time.
An AbortHandler configured or set here overrides the one on LayoutExecutor.
Examples
The most common use case would be to just configure the AbortHandler here, e.g. to set timeouts for a graceful stop or canceling the running layout:
layoutData.abortHandler.stopDuration = TimeSpan.fromSeconds(10) layoutData.abortHandler.cancelDuration = TimeSpan.fromSeconds(30)
layoutData.abortHandler!.stopDuration = TimeSpan.fromSeconds(10) layoutData.abortHandler!.cancelDuration = TimeSpan.fromSeconds(30)
If there's already an AbortHandler instance that's pre-configured or will be used in a different place to, e.g., cancel the layout when the user presses a button, you can also set one explicitly:
layoutData.abortHandler = abortHandler
See Also
Gets or sets the mapping that provides a PreferredPlacementDescriptor instance for edge ILabels.
Examples
Depending on how much customization is needed, some ways of setting PreferredPlacementDescriptors are more convenient than others. For example, to set the same descriptor for all labels, you can just use the constant property:
layoutData.edgeLabelPreferredPlacement = new PreferredPlacementDescriptor({
// Place labels along the edge
angleReference: LabelAngleReferences.RELATIVE_TO_EDGE_FLOW,
angle: 0,
// ... on either side
sideOfEdge: LabelPlacements.LEFT_OF_EDGE | LabelPlacements.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:
// Place label1 orthogonal to the edge anywhere on it
layoutData.edgeLabelPreferredPlacement.mapper.set(
label1,
new PreferredPlacementDescriptor({
placeAlongEdge: LabelPlacements.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.edgeLabelPreferredPlacement.mapper.set(
label2,
new PreferredPlacementDescriptor({
placeAlongEdge: LabelPlacements.AT_SOURCE,
sideOfEdge: LabelPlacements.RIGHT_OF_EDGE | LabelPlacements.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:
layoutData.edgeLabelPreferredPlacement = (label) => {
const customData = label.tag
return new PreferredPlacementDescriptor({
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.
placeAlongEdge: customData.placeInCenter
? LabelPlacements.AT_CENTER
: LabelPlacements.ANYWHERE,
sideOfEdge: customData.placeInCenter
? LabelPlacements.ON_EDGE
: LabelPlacements.LEFT_OF_EDGE | LabelPlacements.RIGHT_OF_EDGE
})
}
layoutData.edgeLabelPreferredPlacement = (
label: ILabel
): PreferredPlacementDescriptor => {
const customData = label.tag
return new PreferredPlacementDescriptor({
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.
placeAlongEdge: customData.placeInCenter
? LabelPlacements.AT_CENTER
: LabelPlacements.ANYWHERE,
sideOfEdge: customData.placeInCenter
? LabelPlacements.ON_EDGE
: LabelPlacements.LEFT_OF_EDGE | LabelPlacements.RIGHT_OF_EDGE
})
}
Note that the preferred placement can also be inferred from an arbitrary ILabelModelParameter:
layoutData.edgeLabelPreferredPlacement =
PreferredPlacementDescriptor.fromParameter(
NinePositionsEdgeLabelModel.CENTER_CENTERED
)
See Also
Gets or sets the collection of nodes whose children should be arranged in an interleaved fashion.
Remarks
Examples
If you already have a collection or IEnumerable<T> containing the nodes whose children should be drawn interleaved, the easiest way is to set the source:
// Place children of selected nodes interleaved
layoutData.interleavedNodes = graphComponent.selection.selectedNodes
If only a few nodes should be configured that way that are not yet in a collection, it's usually easier to use items directly:
layoutData.interleavedNodes.items.add(node1)
layoutData.interleavedNodes.items.add(node2)
If the criteria for which nodes should have their children placed interleaved are readily apparent from each node, then the best option is usually to use the delegate property:
// Place children of nodes with many children interleaved
layoutData.interleavedNodes = (node) => graph.outDegree(node) > 5
// Place children of nodes with many children interleaved
layoutData.interleavedNodes = (node: INode) => graph.outDegree(node) > 5
See Also
Sample Graphs
Gets or sets the mapping from nodes to their NodeHalo.
Remarks
Examples
The easiest option is to reserve the same space around all nodes, by setting a constant NodeHalo:
layoutData.nodeHalos.constant = NodeHalo.create(20)
Handling only certain nodes differently can be done easily by using the mapper property:
// node1 only reserves space above and below
layoutData.nodeHalos.mapper.set(node1, NodeHalo.create(20, 0, 0, 10))
// node2 has space all around
layoutData.nodeHalos.mapper.set(node2, NodeHalo.create(25))
// all other nodes don't get extra space
In cases where the NodeHalo for each node can be determined by looking at the node itself it's often easier to just set a delegate instead of preparing a mapper:
// Retrieve the space around the node from its Tag property
layoutData.nodeHalos = (node) => NodeHalo.create(parseFloat(node.tag))
// Retrieve the space around the node from its Tag property
layoutData.nodeHalos = (node: INode): NodeHalo =>
NodeHalo.create(parseFloat(node.tag))
See Also
Gets or sets the mapping from nodes to an object defining the node type, which influences the ordering of child nodes such that those with same type are preferably placed next to each other.
Remarks
See Also
Sample Graphs
Gets or sets the comparison function used to sort the nodes' outgoing edges.
Remarks
Setting a comparison function sorts the nodes in the same way as the comparer property on the BalloonLayout itself, with the difference that it is possible to use IEdge instances when defining the comparison.
If no comparison function is specified, the outgoing edges are sorted according to the value of property comparer. If that is not set too, then the edges are sorted according to the layout's childOrderingPolicy.
See Also
Gets or sets the mapping for marking the node that will be used as root node of the tree.
Remarks
Examples
The simplest way to set a custom root node for the layout, if you already have an INode for that, would be to use the item to specify it as the root:
layoutData.treeRoot.item = root
In cases where it's easier to look at an INode to determine whether it should be the root node or not, it's often most convenient to use the delegate property:
// This is equivalent to the declaration above
layoutData.treeRoot = (node) => node === root
// Or use a different way of choosing the root node, e.g. by taking the node whose label
// says 'Root'
layoutData.treeRoot = (node) => node.labels.get(0).text === 'Root'
Sometimes there might also be a collection that usually holds just the single node that should be the root, in which case source can be useful:
// Use the first selected node as the root
// This will be evaluated anew each time the layout is applied
layoutData.treeRoot = graphComponent.selection.selectedNodes
See Also
Sample Graphs
Methods
Combines this instance with the given layout data.
Remarks
Parameters
A map of options to pass to the method.
- data - LayoutData
- The LayoutData to combine this instance with.
Returns
- ↪LayoutData
- The combined layout data.