Symmetric layout in Angular Diagram control

23 Aug 20255 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 springLength property 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 springFactor property. 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 property.

Implementation

The following code demonstrates how to arrange nodes using symmetric layout:

import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel, ConnectorModel, LayoutModel, DiagramModule,
  SymmetricLayout, SymmetricLayoutService, BasicShapeModel } from '@syncfusion/ej2-angular-diagrams';

Diagram.Inject(SymmetricLayout);

@Component({
  imports: [DiagramModule],

  providers: [SymmetricLayoutService],
  standalone: true,
  selector: "app-container",
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="590px" [nodes]="nodes"
  [connectors]="connectors" [layout]="layout"> </ejs-diagram>`,
  encapsulation: ViewEncapsulation.None
})
export class AppComponent {

  @ViewChild("diagram")
  public diagram!: DiagramComponent;
  public nodes: NodeModel[] = [];
  public connectors: ConnectorModel[] = [];
  public layout: LayoutModel = {};

  ngOnInit() {
    this.populateNodes();
    this.layout = {
      type: 'SymmetricalLayout',
      springLength: 80,
      springFactor: 0.8,
      maxIteration: 500,
      margin: { left: 20, top: 20 },
    }

  }

  private 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;
  }

  private 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;
  }

  private populateNodes() {
    const parentRect: NodeModel = this.getRectangle('p');
    this.nodes.push(parentRect);
    for (let i = 0; i < 2; i++) {
      const childRect_i: NodeModel = this.getRectangle('c' + i);
      this.nodes.push(childRect_i);
      for (let j = 0; j < 2; j++) {
        const childRect_j: NodeModel = this.getRectangle('c' + i + j);
        this.nodes.push(childRect_j);
        for (let k = 0; k < 6; k++) {
          const childRect_k: NodeModel = this.getRectangle('c' + i + j + k);
          this.nodes.push(childRect_k);
          this.connectors.push(this.connectNodes(childRect_j, childRect_k));
        }
        this.connectors.push(this.connectNodes(childRect_i, childRect_j));
      }
      this.connectors.push(this.connectNodes(parentRect, childRect_i));
    }
    return this.nodes;
  }

}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

NOTE

If you want to use symmetric layout in diagram, you need to inject SymmetricLayout in the diagram.

Symmetric layout