Loading...
The port layout algorithm is a function with the following signature, which returns the relative position of the port relative to the node. For example, if a node is located at { x: 30, y: 40 } on the canvas, and the returned position of a port is { x: 2, y: 4 }, then the port will be rendered at { x: 32, y: 44 } on the canvas.
type Definition<T> = (portsPositionArgs: T[], // layout algorithm parameters specified in the portelemBBox: Rectangle, // bounding box of the nodegroupPositionArgs: T, // default layout algorithm parameters defined in the group) => Result[]interface Result {position: Point.PointLike // relative position to the nodeangle?: number // rotation angle}
Note that when configuring the port ports, we can only configure the layout algorithm through the groups option, and provide optional layout algorithm parameters args in items to affect the layout result.
graph.addNode(...,ports: {// port groupgroups: {group1: {position: {name: 'xxx', // layout algorithm nameargs: { }, // default parameters of the layout algorithm},},},// port definitionitems: [{groups: 'group1',args: { }, // override the default parameters specified in group1},],},)
Let's take a look at how to use the built-in port layout algorithms and how to customize and register custom layout algorithms.
Absolute positioning, specifying the port position through args.
interface AbsoluteArgs {x?: string | numbery?: string | numberangle?: number}
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
| x | string | number | 0 | Relative position on the X-axis. | |
| y | string | number | 0 | Relative position on the Y-axis. | |
| angle | number | 0 | Rotation angle. |
When x and y are percentage strings or between [0, 1], they represent the percentage offset in the width and height directions, otherwise, they represent absolute offsets.
graph.addNode({ports: {groups: {group1: {position: {name: 'absolute',args: { x: 0, y: 0 },},},},items: [{group: 'group1',args: {x: '60%',y: 32,angle: 45,},},],},})
Ports are evenly distributed along the specified edge of the rectangle, and left, right, top, and bottom are four layout algorithms that are very friendly to rectangular nodes. You can set the offset and rotation angle through args.
interface SideArgs {dx?: numberdy?: numberangle?: numberx?: numbery?: number}
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
| strict | boolean | false | Whether to strictly distribute evenly. | |
| dx | number | 0 | Offset in the X-axis direction. | |
| dy | number | 0 | Offset in the Y-axis direction. | |
| angle | number | 0 | Rotation angle. | |
| x | number | - | Override the calculated X-coordinate with the specified value. | |
| y | number | - | Override the calculated Y-coordinate with the specified value. |
graph.addNode({ports: {groups: {group1: {position: 'left',},},items: [{group: 'group1',args: {dx: 2,},},],},})
Ports are evenly distributed along the line segment.
interface LineArgs {start?: Point.PointLikeend?: Point.PointLikedx?: numberdy?: numberangle?: numberx?: numbery?: number}
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
| start | Point.PointLike | Start point of the line segment. | ||
| end | Point.PointLike | End point of the line segment. | ||
| strict | boolean | false | Whether to strictly distribute evenly. | |
| dx | number | 0 | Offset in the X-axis direction. | |
| dy | number | 0 | Offset in the Y-axis direction. | |
| angle | number | 0 | Rotation angle. | |
| x | number | - | Override the calculated X-coordinate with the specified value. | |
| y | number | - | Override the calculated Y-coordinate with the specified value. |
graph.addNode({ports: {groups: {group1: {position: {name: 'line',args: {start: { x: 10, y: 10 },end: { x: 210, y: 10 },},},},},items: [{group: 'group1',args: {dx: 2,},},],},})
Ports are distributed along the ellipse, starting from the start angle, with a step size of step.
interface EllipseArgs {start?: numberstep?: numbercompensateRotate?: booleandr?: numberdx?: numberdy?: numberangle?: numberx?: numbery?: number}
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
| start | number | Start angle. | ||
| step | number | 20 | Step size. | |
| compensateRotate | number | false | Whether to compensate for the rotation angle of the ellipse. | |
| dr | number | 0 | Offset in the radial direction. | |
| dx | number | 0 | Offset in the X-axis direction. | |
| dy | number | 0 | Offset in the Y-axis direction. | |
| angle | number | 0 | Rotation angle. | |
| x | number | - | Override the calculated X-coordinate with the specified value. | |
| y | number | - | Override the calculated Y-coordinate with the specified value. |
const node = graph.addNode({ports: {groups: {group1: {position: {name: 'ellipse',args: {start: 45,},},},},},})Array.from({ length: 10 }).forEach((_, index) => {node.addPort({id: `${index}`,group: 'group1',attrs: { text: { text: index } },})})
Uniformly distributes connection points along an ellipse, starting from the specified angle start.
interface EllipseSpreadArgs {start?: numbercompensateRotate?: booleandr?: numberdx?: numberdy?: numberangle?: numberx?: numbery?: number}
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
| start | number | Starting angle. | ||
| compensateRotate | number | false | Whether to adjust the rotation angle of the connection points along the arc. | |
| dr | number | 0 | Offset along the radial direction. | |
| dx | number | 0 | Offset along the X-axis direction. | |
| dy | number | 0 | Offset along the Y-axis direction. | |
| angle | number | 0 | Rotation angle of the connection points. | |
| x | number | - | Override the X-coordinate of the calculated result with a specified X-coordinate. | |
| y | number | - | Override the Y-coordinate of the calculated result with a specified Y-coordinate. |
const node = graph.addNode({ports: {groups: {group1: {position: {name: 'ellipseSpread',args: {start: 45,},},},},},})Array.from({ length: 36 }).forEach(function (_, index) {ellipse.addPort({group: 'group1',id: `${index}`,attrs: { text: { text: index } },})})
A connection point layout algorithm is a function with the following signature, which returns the relative position of each connection point relative to the node. For example, if a node is located at { x: 30, y: 40 } on the canvas, and the returned position of a connection point is { x: 2, y: 4 }, then the rendered position of the connection point on the canvas would be { x: 32, y: 44 }.
type Definition<T> = (portsPositionArgs: T[], // Layout algorithm parameters specified in the connection pointselemBBox: Rectangle, // Node bounding boxgroupPositionArgs: T, // Default layout algorithm parameters defined in the group) => Result[]interface Result {position: Point.PointLike // Relative position to the nodeangle?: number // Rotation angle}
We can create a custom layout algorithm according to the above rules, for example, implementing a sine distribution layout algorithm:
function sin(portsPositionArgs, elemBBox) {return portsPositionArgs.map((_, index) => {const step = -Math.PI / 8const y = Math.sin(index * step) * 50return {position: {x: index * 12,y: y + elemBBox.height,},angle: 0,}})}
After implementing the layout algorithm, we need to register it to the system. After registration, we can use it like the built-in layout algorithms.
Graph.registerPortLayout('sin', sin)
After registration, we can use it like the built-in layout algorithms:
const rect = graph.addNode({ports: {groups: {sin: {position: {name: 'sin',args: {start: 45,},},attrs: {rect: {fill: '#fe854f',width: 11,},text: {fill: '#fe854f',},circle: {fill: '#fe854f',r: 5,magnet: true,},},},},},})Array.from({ length: 24 }).forEach(() => {rect.addPort({ group: 'sin' })})