Specifies custom data for the OrganicLayout.
Examples
The following example shows how to create a new instance of OrganicLayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel> and use it with an OrganicLayout:
const layoutData = new OrganicLayoutData()
layoutData.preferredEdgeLengths = 45
layoutData.scope.nodes = graphComponent.selection.nodes
graphComponent.graph.applyLayout(new OrganicLayout(), layoutData)
In many cases the complete initialization of OrganicLayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel> can also be done in a single object initializer:
const layoutData = new OrganicLayoutData({
preferredEdgeLengths: 45,
})
layoutData.scope.nodes = graphComponent.selection.nodes
graphComponent.graph.applyLayout(new OrganicLayout(), layoutData)
Type Parameters
- TNode
- TEdge
- TNodeLabel
- TEdgeLabel
Type Details
- yFiles module
- algorithms
Constructors
Parameters
A map of options to pass to the method.
- preferredEdgeLengths - ItemMapping<TEdge,number>
- A mapping from edges to their preferred lengths. This option either sets the value directly or recursively sets properties to the instance of the preferredEdgeLengths property on the created object.
- minimumEdgeLengths - ItemMapping<TEdge,number>
- A mapping from edges to their minimum lengths. This option either sets the value directly or recursively sets properties to the instance of the minimumEdgeLengths property on the created object.
- constraints - OrganicConstraintData<TNode>
- The OrganicConstraintData<TNode> that allows to define additional constraints on the nodes of a graph that will be applied by the OrganicLayout during the layout calculation. This option sets the constraints property on the created object.
- edgeOrientation - ItemMapping<TEdge,number>
- A mapping from edges to their orientation in the layout. This option either sets the value directly or recursively sets properties to the instance of the edgeOrientation property on the created object.
- minimumNodeDistances - ItemMapping<TNode,number>
- A mapping from nodes to their minimum distances to other nodes around them. This option either sets the value directly or recursively sets properties to the instance of the minimumNodeDistances property on the created object.
- overlappingNodes - ItemCollection<TNode>
- The collection of nodes that are allowed to overlap with other nodes. This option either sets the value directly or recursively sets properties to the instance of the overlappingNodes property on the created object.
- nodeMargins - ItemMapping<TNode,Insets>
- The mapping from nodes to their margins. This option either sets the value directly or recursively sets properties to the instance of the nodeMargins property on the created object.
- nodeTypes - ItemMapping<TNode,any>
- The mapping from nodes to an object defining the node type, which is considered for the detection of star, parallel, chain, and cycle substructures. This option either sets the value directly or recursively sets properties to the instance of the nodeTypes property on the created object.
- layoutGridData - LayoutGridData<TNode,TEdge,TNodeLabel,TEdgeLabel>
- The layoutGridData. This option either sets the value directly or recursively sets properties to the instance of the layoutGridData property on the created object.
- edgeDirectedness - ItemMapping<TEdge,number>
- The mapping from edges to their directedness. This option either sets the value directly or recursively sets properties to the instance of the edgeDirectedness property on the created object.
- substructureSourceGroupIds - ItemMapping<TEdge,any>
- A mapping from edges to an object representing their source edge group. This option either sets the value directly or recursively sets properties to the instance of the substructureSourceGroupIds property on the created object.
- substructureTargetGroupIds - ItemMapping<TEdge,any>
- A mapping from edges to an object representing their target edge group. This option either sets the value directly or recursively sets properties to the instance of the substructureTargetGroupIds property on the created object.
- nodeInertia - ItemMapping<TNode,number>
- The mapping from non-group nodes to their inertia. This option either sets the value directly or recursively sets properties to the instance of the nodeInertia property on the created object.
- nodeStress - ItemMapping<TNode,number>
- The mapping from non-group nodes to their stress value. This option either sets the value directly or recursively sets properties to the instance of the nodeStress property on the created object.
- clusterIds - ItemMapping<TNode,any>
- The mapping from nodes to user-defined cluster IDs, overwriting the predefined clusteringPolicy. This option either sets the value directly or recursively sets properties to the instance of the clusterIds property on the created object.
- edgeLabelPreferredPlacements - ItemMapping<TEdgeLabel,EdgeLabelPreferredPlacement>
- The mapping that provides an EdgeLabelPreferredPlacement instance for edge labels. This option either sets the value directly or recursively sets properties to the instance of the edgeLabelPreferredPlacements property on the created object.
- ports - BasicPortData<TNode,TEdge,TNodeLabel,TEdgeLabel>
- The sub-data that provides a way of influencing the placement of the ports. This option either sets the value directly or recursively sets properties to the instance of the ports property on the created object.
Properties
Gets or sets the mapping from nodes to user-defined cluster IDs, overwriting the predefined clusteringPolicy.
Remarks
If custom clusters are defined via this property, the layout's clusteringPolicy is ignored.
Nodes with equal cluster ID form a cluster, hence, will be placed closer together. The value null
indicates that a node is not part of any cluster.
Examples
A convenient way to define clusters is to set a delegate that returns the cluster identifier for each node, for example, using the tag of the nodes:
// Use the node's tag for cluster assignment.
// Nodes with the same tag are part of the same cluster and, thus, placed close to each other.
layoutData.clusterIds = (node: INode) => node.tag
If the clusters are already given as a collection of the respective nodes, using the mapper is practical:
for (const node of cluster1) {
// First cluster: define a common string as ID for all nodes in the first collection
layoutData.clusterIds.mapper.set(node, 'cluster1')
}
for (const node of cluster2) {
// Second cluster: define a common string as ID for all nodes in the second collection
layoutData.clusterIds.mapper.set(node, 'cluster2')
}
See Also
Gets or sets the OrganicConstraintData<TNode> that allows to define additional constraints on the nodes of a graph that will be applied by the OrganicLayout during the layout calculation.
Gets or sets the mapping from edges to their directedness.
Remarks
This property allows the user to specify hints on the directedness of edges. More precisely, a value of 1
indicates that the edge should be considered to be directed from source to target, a value of -1
that it is directed from target to source, and a value of 0
means that it is undirected.
The specified values are considered during the detection of special substructures, see chainSubstructureStyle, cycleSubstructureStyle, parallelSubstructureStyle and starSubstructureStyle.
Examples
The easiest option is to define all edges with the same directedness:
layoutData.edgeDirectedness = 1
Handling only certain edges differently can be done easily by using the mapper property:
// edge1 should be considered directed
layoutData.edgeDirectedness.mapper.set(edge1, 1)
// edge2 should be considered directed against the flow
layoutData.edgeDirectedness.mapper.set(edge2, -1)
// All other edges not set in the mapper are treated as undirected
In cases where the directedness for each edge can be determined by looking at the edge itself it's often easier to just set a delegate instead of preparing a mapper:
// Treat edges as directed or undirected based on their style's arrowhead
layoutData.edgeDirectedness = (edge: IEdge): 0 | 1 | -1 => {
const style = edge.style as PolylineEdgeStyle
// edges with either no arrows on both ends or an arrow on both ends should be considered undirected
if (
(style.sourceArrow === null && style.targetArrow === null) ||
(style.sourceArrow !== null && style.targetArrow !== null)
) {
return 0
}
// edges with only a target arrow are directed from source to target
if (style.targetArrow !== null) {
return 1
}
// edges with only a source arrow are directed from target to source
if (style.sourceArrow !== null) {
return -1
}
return 0
}
See Also
Gets or sets the mapping that provides an EdgeLabelPreferredPlacement instance for edge labels.
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:
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:
// 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:
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:
layoutData.edgeLabelPreferredPlacements =
EdgeLabelPreferredPlacement.fromParameter(
NinePositionsEdgeLabelModel.CENTER_CENTERED,
)
See Also
Gets or sets a mapping from edges to their orientation in the layout.
Remarks
More precisely, a positive value indicates that the edge should have the same orientation as the layout orientation, a negative value indicates that the edge should have the opposite orientation as the layout orientation, and a value of zero means that the orientation can be chosen arbitrarily by the layout algorithm.
If the edge orientation for an edge is not explicitly mapped in the mapper, it is assumed that it can have an arbitrary orientation.
Examples
Specifying the edge orientation for specific edges can be accomplished easily by using the mapper property:
layoutData.edgeOrientation.mapper.set(edge1, 1.0)
layoutData.edgeOrientation.mapper.set(edge2, -1.0)
// The edge orientation for all other edges is not defined
In cases where the edge orientation can be determined by looking at the edge itself it's often easier to just set a delegate instead of preparing a mapper:
organicLayout.layoutOrientation = LayoutOrientation.TOP_TO_BOTTOM
layoutData.edgeOrientation = (edge) => {
switch (edge.labels.first()!.text) {
case 'downwards':
return 1.0 // edges with label 'downwards' should point from top to bottom
case 'upwards':
return -1.0 // edges with label 'upwards' should point from bottom to top
default:
return 0.0 // for all other edges the algorithm can decide
}
}
Finally, there's also the option to use the same value for all edges:
// all edges should have the same orientation as the layout
layoutData.edgeOrientation = 1.0
See Also
Gets or sets the layoutGridData.
Remarks
Examples
The following sample shows how to assign nodes to layout grid cells simply via cell indices:
// Create four nodes and place them in grid cells in the following way
// +---+---+---+
// | 1 | 2 | 3 |
// +---+---+---+
// | 4 |
// +---+
const gridData = layoutData.layoutGridData
const node1 = graph.createNode()
const node2 = graph.createNode()
const node3 = graph.createNode()
const node4 = graph.createNode()
// Assign the nodes to their rows and columns.
// Note that you don't have to create or use LayoutGrid directly in this case.
// Setting the indices is enough.
gridData.rowIndices.mapper.set(node1, 0)
gridData.rowIndices.mapper.set(node2, 0)
gridData.rowIndices.mapper.set(node3, 0)
gridData.rowIndices.mapper.set(node4, 1)
gridData.columnIndices.mapper.set(node1, 0)
gridData.columnIndices.mapper.set(node2, 1)
gridData.columnIndices.mapper.set(node3, 2)
gridData.columnIndices.mapper.set(node4, 1)
graph.applyLayout(new OrganicLayout(), layoutData)
When used this way there is no need to create a LayoutGrid instance or work with it directly. For more flexibility, e.g. to use cells that span multiple columns or rows, the LayoutGrid can be used as well:
// Create three nodes and place them in grid cells in the following way
// +---+---+
// | 1 | 2 |
// +---+---+
// | 3 |
// +---+---+
const gridData = layoutData.layoutGridData
const node1 = graph.createNode(new Rect(0, 0, 50, 50))
const node2 = graph.createNode(new Rect(0, 0, 50, 50))
const node3 = graph.createNode(new Rect(0, 0, 125, 50))
// Create a new LayoutGrid with two rows and two columns
const grid = new LayoutGrid(2, 2)
// Assign the nodes to their cells
const gridCells = new Mapper<INode, LayoutGridCellDescriptor>()
gridCells.set(node1, grid.createCellDescriptor(0, 0))
gridCells.set(node2, grid.createCellDescriptor(0, 1))
gridCells.set(node3, grid.createRowSpanDescriptor(1))
gridData.layoutGridCellDescriptors = gridCells
graph.applyLayout(new OrganicLayout(), layoutData)
Gets or sets a mapping from edges to their minimum lengths.
Remarks
Examples
Specifying a minimum length for specific edges can be accomplished easily by using the mapper property:
layoutData.minimumEdgeLengths.mapper.set(edge1, 120)
layoutData.minimumEdgeLengths.mapper.set(edge2, 75)
// All other edges not set in the mapper implicitly get the default value 0
In cases where the minimum length can be determined by looking at the edge itself it's often easier to just set a delegate instead of preparing a mapper:
// Ensure that there is enough space for the edge's label.
// We'll assume that every edge has a label here.
layoutData.minimumEdgeLengths = (edge) =>
edge.labels.first()!.preferredSize.width * 1.2
Finally, there's also the option to use the same value for all edges:
layoutData.minimumEdgeLengths = 120
See Also
Gets or sets a mapping from nodes to their minimum distances to other nodes around them.
Remarks
This setting only has an effect when allowNodeOverlaps is false
and only applies to the post-processing step that moves overlapping nodes. So the distances from a node that never had overlaps to begin with, may not follow this setting.
Minimum distance values must be greater than 0
.
Examples
Specifying a minimum node distance for specific nodes, overriding the default setting on OrganicLayout can be accomplished easily by using the mapper property:
layoutData.minimumNodeDistances.mapper.set(node1, 25)
layoutData.minimumNodeDistances.mapper.set(node2, 45)
// All other edges not set in the mapper implicitly get the default value
// from OrganicLayout.minimumNodeDistance.
In cases where the minimum distance can be determined by looking at the node itself it's often easier to just set a delegate instead of preparing a mapper:
// Scale the minimum distance around a node by the node size.
// This ensures that larger nodes get more space.
layoutData.minimumNodeDistances = (node) =>
Math.max(node.layout.width, node.layout.height)
Finally, there's also the somewhat nonsensical option to use the same value for all edges, which, as the comment notes, can be achieved easier by just setting the respective property on OrganicLayout:
layoutData.minimumNodeDistances = 25
// This is equivalent to the following property on OrganicLayout:
organicLayout.defaultMinimumNodeDistance = 25
See Also
Sample Graphs
Gets or sets the mapping from non-group nodes to their inertia.
Remarks
[0,1]
. For nodes of sub-structures the inertia value is not considered. The default inertia value is 0.0
and applied if no inertia values are defined or if a node has no individual value.- 1.0 – The node will not move.
- 0.5 – The node will only move half as far as it would with an inertia of
0.0
. - 0.0 – The node will move as fast as possible.
Examples
The easiest option is to define the same inertia for all nodes:
// Allow only a little movement for all nodes
layoutData.nodeInertia = 0.9
Handling only certain nodes differently can be done easily by using the mapper property:
layoutData.nodeInertia.mapper.set(node1, 0.3)
layoutData.nodeInertia.mapper.set(node2, 0.7)
// All other edges not set in the mapper implicitly get
// the default value 0.0
In cases where the inertia 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:
// Move only the selected nodes
layoutData.nodeInertia = (node: INode): 0 | 1 =>
graphComponent.selection.includes(node) ? 0.0 : 1.0
See Also
0.0
, the algorithm considers the initial coordinates of the nodes.Gets or sets the mapping from nodes to their margins.
Remarks
Examples
The easiest option is to reserve the same space around all nodes, by setting a constant value:
layoutData.nodeMargins = new Insets(20)
Handling only certain nodes differently can be done easily by using the mapper property:
// node1 only reserves space above and below
layoutData.nodeMargins.mapper.set(node1, new Insets(20, 10, 0, 0))
// node2 has space all around
layoutData.nodeMargins.mapper.set(node2, new Insets(25))
// all other nodes don't get extra space
In cases where the nodeMargins for each node can be determined by looking at the node itself it's often easier to just set a mapperFunction instead of preparing a mapper:
// Retrieve the space around the node from its tag property
layoutData.nodeMargins = (node: INode): Insets =>
new Insets(parseFloat(node.tag))
See Also
Gets or sets the mapping from non-group nodes to their stress value.
Remarks
The stress value indicates how far a node will possibly move. The higher the stress of a node is, the farther it may move.
The stress can be specified if all nodes are in the scope of the OrganicLayout. It is defined to be a value from the interval [0,1]
. For nodes of sub-structures the stress value is not considered. The default stress value is 1.0
and applied if no stress values are defined or if a node has no individual value.
Examples
The easiest option is to define the same stress for all nodes:
// All nodes should not move too far away
layoutData.nodeStress = 0.3
Handling only certain nodes differently can be done easily by using the mapper property:
layoutData.nodeStress.mapper.set(node1, 0.3)
layoutData.nodeStress.mapper.set(node2, 0.7)
// All other edges not set in the mapper implicitly get
// the default value 1.0
In cases where the inertia 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:
// Move only the selected nodes
layoutData.nodeStress = (node: INode): 0 | 1 =>
graphComponent.selection.includes(node) ? 1.0 : 0.0
See Also
1.0
, the algorithm considers the initial coordinates of the nodes.Gets or sets the mapping from nodes to an object defining the node type, which is considered for the detection of star, parallel, chain, and cycle substructures.
Remarks
If node types are defined, only nodes of the same type or nodes which all have no type can form a substructure.
For parallel substructures, property parallelSubstructureTypeSeparation controls whether parallel substructures are strictly separated by type or if a structure may contain nodes of different types but the substructure layout itself takes care that different types are visually separated (e.g. by placing nodes of the same type closer together or on the same circle).
The same does property starSubstructureTypeSeparation for star substructures.
See Also
Sample Graphs
Gets or sets the collection of nodes that are allowed to overlap with other nodes.
Remarks
Examples
Specifying the property for specific nodes, overriding the default setting on OrganicLayout can be accomplished easily by using the items property:
layoutData.overlappingNodes.items.add(node1)
layoutData.overlappingNodes.items.add(node2)
In cases where the property can be determined by looking at the node itself, it's often easier to just set a delegate instead of adding it to the items:
// Only nodes with a specific area are considered when resolving overlaps.
layoutData.overlappingNodes = (node) =>
node.layout.width * node.layout.height <= 10
See Also
false
.Gets or sets the sub-data that provides a way of influencing the placement of the ports.
Remarks
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.
Gets or sets a mapping from edges to their preferred lengths.
Remarks
0
or a negative value, the default value from defaultPreferredEdgeLength will be used instead.Examples
Specifying a preferred length for specific edges, overriding the default setting on OrganicLayout can be accomplished easily by using the mapper property:
layoutData.preferredEdgeLengths.mapper.set(edge1, 120)
layoutData.preferredEdgeLengths.mapper.set(edge2, 75)
// All other edges not set in the mapper implicitly get the default value
// from OrganicLayout.preferredEdgeLength.
In cases where the preferred length can be determined by looking at the edge itself it's often easier to just set a delegate instead of preparing a mapper:
// Ensure that there is enough space for the edge's label.
// We'll assume that every edge has a label here.
layoutData.preferredEdgeLengths = (edge) =>
edge.labels.get(0).preferredSize.width * 1.2
Finally, there's also the somewhat nonsensical option to use the same value for all edges, which, as the comment notes, can be achieved easier by just setting the respective property on OrganicLayout:
layoutData.preferredEdgeLengths = 120
// This is equivalent to the following property on OrganicLayout:
organicLayout.defaultPreferredEdgeLength = 120
See Also
Sample Graphs
Gets or sets the sub-data that specifies the subset of nodes that is moved by the OrganicLayout.
Examples
Defining the subset of nodes that should be laid out can be done in various ways, mostly depending on which option is more convenient for a particular use case. You can use the ItemCollection<TItem>'s source property to use any .NET collection or IEnumerable<T>:
const layoutData = new OrganicLayoutData()
layoutData.scope.nodes = graphComponent.selection.nodes
Alternatively, ItemCollection<TItem> also has an items property, which is a collection that already exists, in case the items may have to be added one by one. This can be more convenient than defining an own list and setting it to source:
for (const edge of graphComponent.selection.edges) {
layoutData.scope.nodes.items.add(edge.sourceNode)
layoutData.scope.nodes.items.add(edge.targetNode)
}
A powerful option that doesn't use a collection is to use the predicate to set a custom delegate that returns for every node whether it is contained in the set or not:
// We assume here that all nodes have a CustomData instance as their tag,
// which then has a boolean property 'IncludeInLayout'.
layoutData.scope.scopeModes = (node) =>
(node.tag as CustomData).includeInLayout
? OrganicScope.AFFECTED
: OrganicScope.FIXED
See Also
Gets or sets a mapping from edges to an object representing their source edge group.
Remarks
- When the star substructure style SEPARATED_RADIAL is applied, edges grouped at the root node are drawn in a grouped routing style.
- When one of the parallel substructure styles RECTANGULAR, RADIAL or STRAIGHT_LINE is applied, then edges of the parallel structures may be grouped at their outer nodes.
Examples
One simple way to use source groups is to use the edge's source node as group ID which effectively groups all edges with the same source together:
layoutData.sourceGroupIds = (edge: IEdge) => edge.sourceNode
Another useful way to use a delegate here would be grouping edges by some commonality, such as the same color:
layoutData.sourceGroupIds = (edge: IEdge) => {
const style = edge.style
if (style instanceof PolylineEdgeStyle) {
return style.stroke!.fill
}
return null
}
If only certain edges should be grouped it may sometimes be easier to use the mapper to set the group IDs:
for (const group of edgeGroups) {
for (const edge of group) {
// Use the collection as group ID, since it's common to all edges in it
layoutData.sourceGroupIds.mapper.set(edge, group)
}
}
See Also
Gets or sets a mapping from edges to an object representing their target edge group.
Remarks
- When the star substructure style SEPARATED_RADIAL is applied, edges grouped at the root node are drawn in a grouped routing style.
- When one of the parallel substructure styles RECTANGULAR, RADIAL or STRAIGHT_LINE is applied, then edges of the parallel structures may be grouped at their outer nodes.
Examples
One simple way to use source groups is to use the edge's target node as group ID which effectively groups all edges with the same target together:
layoutData.targetGroupIds = (edge: IEdge) => edge.targetNode
Another useful way to use a delegate here would be grouping edges by some commonality, such as the same color:
layoutData.targetGroupIds = (edge: IEdge) => {
const style = edge.style
if (style instanceof PolylineEdgeStyle) {
return style.stroke!.fill
}
return null
}
If only certain edges should be grouped it may sometimes be easier to use the mapper to set the group IDs:
for (const group of edgeGroups) {
for (const edge of group) {
// Use the collection as group ID, since it's common to all edges in it
layoutData.targetGroupIds.mapper.set(edge, group)
}
}
See Also
Gets a mapper from non-group nodes to the computed center z-coordinate in case that a 3D layout was created.
Remarks
The mapper is filled by the layout with the computed z-coordinates of the non-group nodes. The node's world coordinates provide the matching x and y coordinates.
This is only required if create3DLayout is enabled. Otherwise, the algorithm produces a 2D result.
Examples
const layoutData = new OrganicLayoutData()
const layout = new OrganicLayout()
// Enable creating a 3D result
layout.create3DLayout = true
graph.applyLayout(layout, layoutData)
for (const node of graph.nodes) {
// Print z-coordinate for all non-group nodes
if (!graph.isGroupNode(node)) {
console.log(
`Node ${node} has z-coordinate ${layoutData.zCoordinatesResult.get(node)}`,
)
}
}
See Also
Methods
combineWith
(data: LayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel>…) : LayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel>Combines this instance with the given layout data.
Remarks
Parameters
A map of options to pass to the method.
- data - LayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel>
- The LayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel> to combine this instance with.
Returns
- ↪LayoutData<TNode,TEdge,TNodeLabel,TEdgeLabel>
- The combined layout data.