// getting a node's coordinates and size
const nl = node.layout
const x = nl.x
const y = nl.y
const width = nl.width
const height = nl.height
// set the top left corner of the node
node.layout.topLeft = new Point(x + 10, y + 10)
// move the node
node.layout.x += 10
node.layout.y -= 10
// set the center of the node
node.layout.center = new Point(20, 20)
// set the size of the node
node.layout.size = new Size(width * 2, height * 2)
// set the whole layout of the node at once by providing a rectangle
node.layout.bounds = new Rect(x, y, width, height)
The LayoutGraph API - Part 2: Layout
The LayoutGraph type manages the positional and dimensional information of its elements, namely LayoutNodes, LayoutEdges, LayoutNodeLabels, and LayoutEdgeLabels. It is used by the automatic layouts in yFiles.
Nodes
The NodeLayout type is used to add or query the layout information for a node.
This information includes the coordinates of the upper-left corner of the node, as well as its width and height.
The following convenient properties of NodeLayout can be used to control the layout information for nodes:
Edges
The LayoutEdge type holds the layout information for an edge, among other data.
This information includes the coordinates for the starting point (source port) and end point (target port) of the edge path, as well as the coordinates for the bends (also known as control points) between the source and target ports. Bends are points that divide edges into segments.
Tip
|
The coordinates for the edge’s end points are provided both as absolute coordinates and as coordinates relative to the center of the edge’s source and target nodes. The coordinates for the bends, however, are absolute. |
The following convenient properties of the LayoutEdge can be used to control its layout information. Note that the pathPoints of an edge include its source port, all bends, and its target port. In this case, the source and target port locations are absolute coordinates. The property bends, on the other hand, contains only the edge’s bends.
const edge = graph.createEdge(node1, node2)
// Set the edge's source point at the top center of node1 using absolute coordinates
const topCenterAbsolute = new Point(node1.layout.centerX, node1.layout.y)
edge.sourcePortLocation = topCenterAbsolute
// Set the edge's target point at the bottom center of node2 using relative coordinates
// Note that the coordinates are relative to the *center* of the node
const bottomCenterRelative = new Point(0, node2.layout.height / 2)
edge.targetPortOffset = bottomCenterRelative
const sourceLayout = node1.layout
const targetLayout = node2.layout
// Now add the bends
graph.addBend(edge, sourceLayout.centerX, sourceLayout.y - 100)
graph.addBend(edge, sourceLayout.x, sourceLayout.y - 100)
graph.addBend(
edge,
sourceLayout.x,
targetLayout.y + targetLayout.width + 100
)
graph.addBend(
edge,
targetLayout.centerX,
targetLayout.y + targetLayout.width + 100
)
Coordinates of an existing edge path can also be changed by modifying the X and Y properties of the EdgePathPoint instances accessible via LayoutEdge.pathPoints.
Labels
Labels in a LayoutGraph are represented by the types LayoutNodeLabel and LayoutEdgeLabel, depending on the type of their owner. Among other information, the labels contain their layout information as an IOrientedRectangle in absolute coordinates. Despite this, labels move with their owner when the owner is repositioned.
Labels can be added to or removed from a LayoutGraph using overloads of the following methods:
const graph = getMyLayoutGraph()
// create a node label
const node = graph.nodes.first()
const nodeLabel = graph.addLabel(
node,
new OrientedRectangle(0, 0, 80, 20)
)
// create an edge label
const edge = graph.edges.first()
const edgeLabel = graph.addLabel(
edge,
new OrientedRectangle(0, 0, 80, 20)
)
// remove the node label
graph.remove(nodeLabel)
Applying a Layout on LayoutGraph
To apply an ILayoutAlgorithm or ILayoutStage on an instance of LayoutGraph, use the method applyLayout.
const graph = getMyLayoutGraph()
// Create a tree layout algorithm and corresponding layout data
const treeLayout = new TreeLayout()
const layoutData = treeLayout.createLayoutData(graph)
// Apply them to the layout graph
graph.applyLayout(treeLayout, layoutData)
Using Buffered Layout
Important
|
This section applies only to yFiles layout packages! The IGraph-based adapter mechanism already creates the layout graph as a copy of the original IGraph and thus provides the same conceptual benefits as buffered layout. |
With the yFiles for HTML layout algorithms, it is possible to have a graph layout calculated using two different approaches: unbuffered layout or buffered layout.
Unbuffered layout means directly invoking a layout algorithm’s applyLayout method. Choosing this approach means that the layout calculation is performed on the given graph and is also immediately assigned.
A buffered layout, in contrast, is performed on a copy of the original graph and is then applied to the original graph after the layout calculation.
Unbuffered layouts have some drawbacks that should be observed:
-
Some layout algorithms need to temporarily add or remove nodes or edges to or from the given graph. While it is guaranteed that a layout algorithm will not change a graph’s node set and edge set, it is not unusual that the ordering of nodes and/or edges is modified. Consequently, it is not safe to rely on consistent indices of nodes or edges in unbuffered layouts.
-
In rare cases, a layout algorithm might crash during a calculation (due to a bug, for example). It will then return immediately and generate an exception. The input graph will be left in an intermediate, often broken state, and no recovery will be possible for it.
-
Directly invoking a layout algorithm’s applyLayout method will not return the calculated coordinates but instead assign them right away to the given graph. Consequently, any other way of coordinate assignment, for example, in an animated fashion using coordinate interpolation, is made impossible.
const graph = getMyLayoutGraph()
// Copy the graph
const copiedGraph = LayoutGraph.createCopy(graph)
// Run e.g. organic layout on the copied graph
new OrganicLayout().applyLayout(copiedGraph)
// Write back the changes to the original graph
copiedGraph.context.graphCopyData!.commitLayoutToOriginalGraph()