Specifies custom data for constraining the port placement.
Type Parameters
- TNode
- TEdge
- TNodeLabel
- TEdgeLabel
Type Details
- yFiles module
- algorithms
See Also
Constructors
Parameters
A map of options to pass to the method.
- sourcePortCandidates - ItemMapping<TEdge,EdgePortCandidates>
- A mapping from edges to their source port candidates. This option either sets the value directly or recursively sets properties to the instance of the sourcePortCandidates property on the created object.
- targetPortCandidates - ItemMapping<TEdge,EdgePortCandidates>
- A mapping from edges to their target port candidates. This option either sets the value directly or recursively sets properties to the instance of the targetPortCandidates property on the created object.
- nodePortCandidates - ItemMapping<TNode,NodePortCandidates>
- A mapping from nodes to their NodePortCandidates. This option either sets the value directly or recursively sets properties to the instance of the nodePortCandidates property on the created object.
- sourcePortGroupIds - ItemMapping<TEdge,any>
- A mapping from edges to an object representing their source port group. This option either sets the value directly or recursively sets properties to the instance of the sourcePortGroupIds property on the created object.
- targetPortGroupIds - ItemMapping<TEdge,any>
- A mapping from edges to an object representing their target port group. This option either sets the value directly or recursively sets properties to the instance of the targetPortGroupIds property on the created object.
Properties
Gets or sets a mapping from nodes to their NodePortCandidates.
Remarks
Examples
The simplest way to define node port candidates is to use the same NodePortCandidates for all nodes, if suitable for the use case:
// All nodes get only a candidate for the lower (Bottom) side with capacity 10
const constantPortCandidates = new NodePortCandidates().addFreeCandidate(
PortSides.BOTTOM,
10,
)
layoutData.ports.nodePortCandidates = constantPortCandidates
The same effect can be achieved with a delegate as well. However, a more useful way to use a delegate would be to decide whether a node should get node port candidates based on some data at the node, e.g., found in its tag:
// Create a PortCandidateSet with capacity 2 for the upper side (Top) and capacity 1 for the lower side (Bottom)
const pcs = new NodePortCandidates()
.addFreeCandidate({
side: PortSides.TOP,
capacity: 2,
})
.addFreeCandidate(PortSides.BOTTOM)
// Specify the node port candidates for diamond nodes, i.e. for nodes with the string "diamond" in their tag
layoutData.ports.nodePortCandidates = (node) =>
node.tag === 'diamond' ? pcs : null!
If specific nodes should get certain NodePortCandidates, it may sometimes be easier to use the mapper to set them:
// Create node port candidate set with capacity 2 for the top side and capacity 1 for the bottom side
const pcs1 = new NodePortCandidates()
.addFreeCandidate({ side: PortSides.TOP, capacity: 2 })
.addFreeCandidate(PortSides.BOTTOM)
// Create another set with candidates for the left and right side
const pcs2 = new NodePortCandidates()
.addFreeCandidate({
side: PortSides.RIGHT,
capacity: 4,
})
.addFreeCandidate({
side: PortSides.LEFT,
capacity: 4,
})
// Specify the port candidates for two specific nodes
layoutData.ports.nodePortCandidates.mapper.set(node1, pcs1)
layoutData.ports.nodePortCandidates.mapper.set(node2, pcs2)
See Also
Gets or sets a mapping from edges to their source port candidates.
Remarks
LayoutPortCandidates allow to define where an edge can connect to its source node and allow fine control over port placement.
If candidates are assigned to edges (e.g. with this property) and to nodes (nodePortCandidates), the layout algorithm tries to match them. The exact procedure depends on the layout algorithm.
Examples
Source port candidates are effectively a collection of possible port placements with different costs and the layout algorithm is free to choose the candidate that fits best into the overall layout, while also preferring candidates with a lower cost. To set the same candidate list for all edges, it's easiest to use the constant property:
// Prefer the center position and route the edge downwards if possible (no cost for this candidate)
const candidates = new EdgePortCandidates().addFixedCandidate(
PortSides.BOTTOM,
Point.ORIGIN,
)
// Alternatively, use any position at the bottom border of the node, but with a higher cost
candidates.addFreeCandidate(PortSides.BOTTOM, 1)
// If that fails, use either the left or the right side
candidates
.addFreeCandidate(PortSides.LEFT, 2)
.addFreeCandidate(PortSides.RIGHT, 2)
layoutData.ports.sourcePortCandidates = candidates
If certain edges need specific port candidates, it's usually convenient to use the mapper property:
// edge1 should leave the source node preferably on the node side in flow direction,
// but can also use a fixed port location on the left of the node.
layoutData.ports.sourcePortCandidates.mapper.set(
edge1,
new EdgePortCandidates()
.addFreeCandidate(PortSides.END_IN_FLOW)
.addFixedCandidate(PortSides.LEFT, new Point(-0.5, 0.25), 1),
)
// edge2 should leave the source node anywhere on the upper side of the node
layoutData.ports.sourcePortCandidates.mapper.set(
edge2,
new EdgePortCandidates().addFreeCandidate(PortSides.TOP),
)
For cases when the desired configuration of port candidates can be readily created from the edge itself, the mapperFunction is often the most convenient option:
// Assume that edges may have "yes" or "no" labels and specify port candidates based on label text
layoutData.ports.sourcePortCandidates = (edge) => {
switch (edge.labels.at(0)?.text) {
case 'Yes':
return new EdgePortCandidates().addFreeCandidate(PortSides.RIGHT)
case 'No':
return new EdgePortCandidates().addFreeCandidate(PortSides.LEFT)
default:
return new EdgePortCandidates()
.addFreeCandidate(PortSides.TOP)
.addFreeCandidate(PortSides.BOTTOM)
}
}
See Also
Sample Graphs
Gets or sets a mapping from edges to an object representing their source port group.
Remarks
Examples
The simplest way to use source port groups is to use the same object as port group ID for all edges. Since grouping is done per node, this has the effect of grouping all edges with the same source node together:
layoutData.ports.sourcePortGroupIds = {}
The same effect can be achieved with a delegate as well, by returning the source node as the port group ID for each edge. However, a more useful way to use a delegate here would be grouping edges by some commonality, such as the same color:
layoutData.ports.sourcePortGroupIds = (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 port group IDs:
for (const group of edgePortGroups) {
for (const edge of group) {
// Use the collection as group ID, since it's common to all edges in it
layoutData.ports.sourcePortGroupIds.mapper.set(edge, group)
}
}
See Also
Gets or sets a mapping from edges to their target port candidates.
Remarks
LayoutPortCandidates allow to define where an edge can connect to its target node and allow fine control over port placement.
If candidates are assigned to edges (e.g. with this property) and to nodes (nodePortCandidates), the layout algorithm tries to match them. The exact procedure depends on the layout algorithm.
Examples
Target port candidates are effectively a collection of possible port placements with different costs and the layout algorithm is free to choose the candidate that fits best into the overall layout, while also preferring candidates with a lower cost. To set the same candidate list for all edges, it's easiest to use the constant property:
const candidates = new EdgePortCandidates()
// Prefer the center position and enter the node from the top if possible (no cost for this candidate)
new EdgePortCandidates()
.addFixedCandidate(PortSides.TOP, [0, 0])
// Alternatively, use any position at the top border of the node, but with a higher cost
.addFreeCandidate(PortSides.TOP, 1)
// If that fails, use either the left or the right side
.addFreeCandidate(PortSides.LEFT, 2)
.addFreeCandidate(PortSides.RIGHT, 2)
If certain edges need specific port candidates, it's usually convenient to use the mapper property:
// edge1 should enter the target node preferably on the node side in flow direction,
// but can also use a fixed port location on the left of the node.
layoutData.ports.targetPortCandidates.mapper.set(
edge1,
new EdgePortCandidates()
.addFreeCandidate(PortSides.END_IN_FLOW)
.addFixedCandidate(PortSides.LEFT, new Point(-0.5, -0.25), 1),
)
// edge2 should enter the target node anywhere on the bottom side of the node
layoutData.ports.targetPortCandidates.mapper.set(
edge2,
new EdgePortCandidates().addFreeCandidate(PortSides.BOTTOM),
)
For cases when the desired configuration of port candidates can be readily created from the edge itself, the mapperFunction is often the most convenient option:
// Assume that edges may have "yes" or "no" labels and specify port candidates based on label text
layoutData.ports.targetPortCandidates = (edge) => {
switch (edge.labels.at(0)?.text) {
case 'Yes':
return new EdgePortCandidates().addFreeCandidate(PortSides.RIGHT)
case 'No':
return new EdgePortCandidates().addFreeCandidate(PortSides.LEFT)
default:
return new EdgePortCandidates()
.addFreeCandidate(PortSides.TOP)
.addFreeCandidate(PortSides.BOTTOM)
}
}
See Also
Sample Graphs
Gets or sets a mapping from edges to an object representing their target port group.
Remarks
Examples
The simplest way to use target port groups is to use the same object as port group ID for all edges. Since grouping is done per node, this has the effect of grouping all edges with the same target node together:
layoutData.ports.targetPortGroupIds = {}
The same effect can be achieved with a delegate as well, by returning the target node as the port group ID for each edge. However, a more useful way to use a delegate here would be grouping edges by some commonality, such as the same color:
layoutData.ports.targetPortGroupIds = (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 port group IDs:
for (const group of edgePortGroups) {
for (const edge of group) {
// Use the collection as group ID, since it's common to all edges in it
layoutData.ports.targetPortGroupIds.mapper.set(edge, group)
}
}
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.