Symmetric Layout in React Diagram Component
21 Oct 202511 minutes to read
The symmetric layout is a force-directed algorithm that positions nodes by simulating physical forces between them. Nodes are repositioned iteratively by moving them closer together or pushing them further apart until the system reaches an equilibrium state, creating a balanced and visually appealing arrangement.
Understanding Symmetric Layout
Symmetric layout works by applying spring-like forces between connected nodes and repulsion forces between all nodes. This creates a natural, organic layout where strongly connected components cluster together while maintaining proper spacing throughout the diagram.
The layout’s springLengthproperty defines the ideal length that edges should maintain. This serves as the resting length for the springs connecting nodes.
Edge attraction and vertex repulsion forces are controlled using the layout’s springFactorproperty. Higher values cause sibling nodes to repel each other more strongly, creating greater separation between unconnected elements.
The algorithm continues iterating until node positions stabilize and relative positions no longer change significantly between iterations. You can control the maximum number of iterations using the layout’s maxIteration.
Implementation
The following code demonstrates how to arrange nodes using symmetric layout:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, SymmetricLayout } from '@syncfusion/ej2-react-diagrams';
//Initialize nodes
let nodes = [];
//Initializes connectors
let connectors = [];
// creating the connection between the layout nodes and connectors.
function connectNodes(parentNode, childNode) {
const connector = {
id: parentNode.id + childNode.id,
sourceID: parentNode.id,
targetID: childNode.id,
targetDecorator: { shape: 'None' },
};
return connector;
}
// creating the layout nodes as rectangle in shape.
function getRectangle(name) {
const shape = { type: 'Basic', shape: 'Ellipse' };
const node = {
id: name,
height: 25,
width: 25,
style: { fill: '#ff6329' },
shape: shape,
};
return node;
}
// creating the symmetrical layout child elements hierarchy.
function populateNodes() {
const parentRect = getRectangle('p');
nodes.push(parentRect);
for (let i = 0; i < 2; i++) {
const childRect_i = getRectangle('c' + i);
nodes.push(childRect_i);
for (let j = 0; j < 2; j++) {
const childRect_j = getRectangle('c' + i + j);
nodes.push(childRect_j);
for (let k = 0; k < 6; k++) {
const childRect_k = getRectangle('c' + i + j + k);
nodes.push(childRect_k);
connectors.push(connectNodes(childRect_j, childRect_k));
}
connectors.push(connectNodes(childRect_i, childRect_j));
}
connectors.push(connectNodes(parentRect, childRect_i));
}
return nodes;
}
//sets the layout child elements
populateNodes();
export default function App() {
return (
<div>
<DiagramComponent
id="container"
width={'80%'}
height={'550px'}
nodes={nodes}
connectors={connectors}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'SymmetricalLayout',
springLength: 80,
springFactor: 0.8,
maxIteration: 500,
margin: { left: 20, top: 20 },
}}
>
{/* Inject necessary services for the diagram */}
<Inject services={[SymmetricLayout]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, SymmetricLayout, ConnectorModel, NodeModel, BasicShapeModel } from '@syncfusion/ej2-react-diagrams';
//Initialize nodes
let nodes: NodeModel[] = [];
//Initializes connectors
let connectors: ConnectorModel[] = [];
// creating the connection between the layout nodes and connectors.
function connectNodes(parentNode: NodeModel | any, childNode: NodeModel): ConnectorModel {
const connector: ConnectorModel = {
id: parentNode.id + childNode.id,
sourceID: parentNode.id,
targetID: childNode.id,
targetDecorator: { shape: 'None' },
};
return connector;
}
// creating the layout nodes as rectangle in shape.
function getRectangle(name: string): NodeModel {
const shape: BasicShapeModel = {
type: 'Basic',
shape: 'Ellipse',
};
const node: NodeModel = {
id: name,
height: 25,
width: 25,
style: { fill: '#ff6329' },
shape: shape,
};
return node;
}
// creating the symmetrical layout child elements hierarchy.
function populateNodes() {
const parentRect: NodeModel = getRectangle('p');
nodes.push(parentRect);
for (let i = 0; i < 2; i++) {
const childRect_i: NodeModel = getRectangle('c' + i);
nodes.push(childRect_i);
for (let j = 0; j < 2; j++) {
const childRect_j: NodeModel = getRectangle('c' + i + j);
nodes.push(childRect_j);
for (let k = 0; k < 6; k++) {
const childRect_k: NodeModel = getRectangle('c' + i + j + k);
nodes.push(childRect_k);
connectors.push(connectNodes(childRect_j, childRect_k));
}
connectors.push(connectNodes(childRect_i, childRect_j));
}
connectors.push(connectNodes(parentRect, childRect_i));
}
return nodes;
}
//sets the layout child elements
populateNodes();
export default function App() {
return (
<div>
<DiagramComponent
id="container"
width={'80%'}
height={'550px'}
nodes={nodes}
connectors={connectors}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'SymmetricalLayout',
springLength: 80,
springFactor: 0.8,
maxIteration: 500,
margin: { left: 20, top: 20 },
}}
>
{/* Inject necessary services for the diagram */}
<Inject services={[SymmetricLayout]} />
</DiagramComponent>
</div>
);
}
// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById('diagram') as HTMLElement);
root.render(<App />);Note: If you want to use symmetric layout in diagram, you need to inject SymmetricLayout in the diagram.
