Group in Angular Diagram Component
25 Aug 202524 minutes to read
Groups enable developers to cluster multiple nodes and connectors into a single manageable element, acting as a container that maintains relationships between child elements while allowing both collective and individual manipulation. This powerful feature streamlines complex diagram management by treating related elements as cohesive units while preserving the ability to edit individual components when needed.
Create group
A group functions as a container for its children (nodes, groups, and connectors). Every change made to the group affects all children proportionally, while child elements remain individually editable. Groups can contain other groups, creating nested hierarchies for complex diagram structures.
Add group when initializing diagram
A group can be added to the diagram model through the nodes
collection. To define an object as a group, add the child objects to the children
collection of the group. The following code illustrates how to create a group node.
Important: When creating a group, child nodes must be declared before the group declaration.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel, ShapeStyleModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="600px" [getNodeDefaults] ='getNodeDefaults' [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'rectangle1',
offsetX: 100,
offsetY: 100,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle1',
},
],
},
{
id: 'rectangle2',
offsetX: 200,
offsetY: 200,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle2',
},
],
},
{
id: 'group',
children: ['rectangle1', 'rectangle2'],
},
];
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
((node as NodeModel).style as ShapeStyleModel).strokeColor = "White";
return node;
}
public created(args: Object): void {
(this.diagram as DiagramComponent).select([(this.diagram as DiagramComponent).getObject('group')]);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Connectors can also be added to a group. To create a group using nodes and connectors in the Angular Diagram, refer to the below video link:
The following code illustrates how to add connectors into a group:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild, } from '@angular/core';
import {
DiagramComponent, NodeModel, ConnectorModel,
} from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: 'app-container',
template: `<ejs-diagram #diagram id="diagram" width="1000px" height="700px" [nodes]='nodes' [connectors]="connectors">
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild('diagram')
public diagram?: DiagramComponent;
public connectors: ConnectorModel[] = [{
id: 'connector1', type: 'Orthogonal', sourceID: 'node1', targetID: 'node2'
},
];
public nodes: NodeModel[] = [{
id: 'node1', height: 100, width: 100, offsetX: 100, offsetY: 100, annotations: [{ content: 'Node1' }]
},
{
id: 'node2', height: 100, width: 100, offsetX: 300, offsetY: 100, annotations: [{ content: 'Node2' }]
},
{
id: 'group', children: ['node1', 'node2', 'connector1',], style: { strokeWidth: 0 }
}];
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Runtime group operations
Group nodes at runtime
Groups can be dynamically created during runtime by invoking the diagram.group
method. To initiate this process, first select the nodes that should be included within the group. The diagram.group
method will encapsulate the selected nodes within a newly formed group node.
The following code illustrates how to group nodes at runtime:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<button (click)="group()">group selected nodes</button>
<ejs-diagram #diagram id="diagram" width="100%" height="900px" [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'node1', height: 100, width: 100, offsetX: 100, offsetY: 100, annotations: [{ content: 'Node1' }]
},
{
id: 'node2', height: 100, width: 100, offsetX: 200, offsetY: 200, annotations: [{ content: 'Node2' }]
},
{
id: 'node3', height: 100, width: 100, offsetX: 300, offsetY: 300, annotations: [{ content: 'Node3' }]
},
];
public created(args: Object): void {
(this.diagram as DiagramComponent).selectAll();
}
public group(): void {
// Groups the selected nodes and connectors in the diagram.
(this.diagram as DiagramComponent).group();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Ungroup nodes at runtime
Group nodes can be ungrouped dynamically using the diagram.unGroup
method. This operation dissolves the group container while preserving all child elements as individual diagram elements.
The following code example shows how to ungroup a group node at runtime:
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, NodeModel, Diagram } from '@syncfusion/ej2-angular-diagrams';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<button (click)="unGroup()">unGroup</button>
<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'rectangle1',
offsetX: 100,
offsetY: 100,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle1',
},
],
},
{
id: 'rectangle2',
offsetX: 200,
offsetY: 200,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle2',
},
],
},
{
id: 'group',
children: ['rectangle1', 'rectangle2'],
}
];
public created(args: Object): void {
(this.diagram as DiagramComponent).select([(this.diagram as DiagramComponent).getObject('group')]);
}
public unGroup(): void {
// Ungroups the selected nodes and connectors in the diagram.
(this.diagram as DiagramComponent).unGroup();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Add group node at runtime
A group node can be added at runtime using the diagram method diagram.add
. This method allows programmatic addition of predefined group structures to an existing diagram.
The following code illustrates how a group node is added at runtime:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [nodes]="nodes" (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'rectangle1',
offsetX: 100,
offsetY: 100,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle1',
},
],
},
{
id: 'rectangle2',
offsetX: 200,
offsetY: 200,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle2',
},
],
}
];
public group: NodeModel = {
id: 'group2',
children: ['rectangle1', 'rectangle2']
}
public created(args: Object): void {
// Add the group into the diagram
(this.diagram as DiagramComponent).add(this.group as NodeModel);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Add collection of group nodes at runtime
The collection of group nodes can be dynamically added using the addElements
method. Each time an element is added to the diagram canvas, the collectionChange
event will be triggered.
The following code illustrates how to add group node collections at runtime:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, Diagram, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public group: NodeModel = [
{ id: "rectangle1", offsetX: 100, offsetY: 100, width: 100, height: 100, annotations: [{ content: 'node1' }] },
{ id: "rectangle2", offsetX: 200, offsetY: 200, width: 100, height: 100, annotations: [{ content: 'node2' }] },
{ id: 'group', children: ['rectangle1', 'rectangle2'] },
{ id: "rectangle3", offsetX: 400, offsetY: 400, width: 100, height: 100, annotations: [{ content: 'node1' }] },
{ id: "rectangle4", offsetX: 500, offsetY: 500, width: 100, height: 100, annotations: [{ content: 'node2' }] },
{ id: 'group2', children: ['rectangle3', 'rectangle4'], padding: { left: 10, right: 10, top: 10, bottom: 10 } },
] as NodeModel;
public created(args: Object): void {
// Add the group collection into the diagram
(this.diagram as DiagramComponent).addElements(this.group as any);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Manage group children at runtime
Add children to group at runtime
A child node can be added to a specified group at runtime using the diagram method diagram.addChildToGroup
. This functionality requires passing the group and the existing child node as arguments to the method.
The following code illustrates how a child node can be added to a group node at runtime:
this.diagram.addChildToGroup(groupNode, childNode);
Remove children from group at runtime
A specific child can be removed from a group node at runtime using the diagram method diagram.removeChildFromGroup
. This functionality requires passing the group and its child node as arguments to the method.
The following code illustrates how a child node is removed from a group at runtime:
this.diagram.removeChildFromGroup (groupNode, childNode);
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, DiagramModule, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `
<button (click)="addChild()">addChildToGroup</button>
<button (click)="removeChild()">removeChildFromGroup</button>
<ejs-diagram #diagram id="diagram" width="100%" height="600" [nodes]="nodes" >
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes?: NodeModel[];
ngOnInit(): void {
this.nodes = [
{
id: 'node1', width: 150, height: 100, offsetX: 100, offsetY: 100, annotations: [{ content: 'Node1' }]
}, {
id: 'node2', width: 80, height: 130, offsetX: 200, offsetY: 200, annotations: [{ content: 'Node2' }]
}, {
id: 'group1', children: ['node1', 'node2']
}, {
id: 'node3', width: 100, height: 100, offsetX: 300, offsetY: 300, annotations: [{ content: 'Node3' }]
}
];
}
addChild() {
// Adds the specified diagram object to the specified group node.
/**
* parameter 1 - The group node to which the diagram object will be added.
* parameter 2 - The diagram object to be added to the group.
*/
(this.diagram as DiagramComponent).addChildToGroup(
(this.diagram as DiagramComponent).getObject('group1'),
'node3'
);
}
removeChild() {
// Removes the specified diagram object from the specified group node.
/**
* parameter 1 - The group node from which the diagram object will be removed.
* parameter 2 - The diagram object to be removed from the group.
*/
(this.diagram as DiagramComponent).removeChildFromGroup(
(this.diagram as DiagramComponent).getObject('group1'),
'node3'
);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Group styling and layout
Group padding
The padding
property of a group node defines the spacing between the group node’s edges and its children. This property helps maintain visual separation and improves the overall appearance of grouped elements.
The following code illustrates how to add padding to a node group:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, DiagramModule, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'node1',
width: 100,
height: 100,
offsetX: 100,
offsetY: 100,
annotations: [{ content: 'Node1' }],
},
{
id: 'node2',
width: 100,
height: 100,
offsetX: 200,
offsetY: 200,
annotations: [{ content: 'Node2' }],
},
{
id: 'node3',
width: 100,
height: 100,
offsetX: 300,
offsetY: 300,
annotations: [{ content: 'Node3' }],
},
{
id: 'group',
children: ['node1', 'node2', 'node3'],
// Defines the space between the group node edges and its children
padding: { left: 20, right: 20, top: 20, bottom: 20 },
}
];
public created(args: Object): void {
(this.diagram as DiagramComponent).select([(this.diagram as DiagramComponent).getObject('group')]);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Group flip
The flip functionality for a group node works similarly to that of normal nodes. When flipping a group node, the child nodes inherit the group’s flip transformation while retaining their individual flip settings. The combined effect creates a hierarchical flip behavior where both the group and child transformations are applied.
Example of combined flip behavior:
- If a child node’s flip is set to Vertical and the group node’s flip is set to Horizontal, the resulting flip for the child node combines both transformations (effectively a “both” flip)
- This ensures that child nodes adapt dynamically based on the group’s flip while maintaining their unique flip settings
The following example shows how to apply flip transformations to group nodes:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, DiagramModule, NodeModel, FlipDirection } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'node1',
width: 70,
height: 70,
offsetX: 100,
offsetY: 100,
//Sets the flip as Vertical
flip: FlipDirection.Vertical,
shape: {
type: 'Basic',
shape: 'RightTriangle',
},
style: {
fill: '#6BA5D7',
},
},
{
id: 'node2',
width: 70,
height: 70,
offsetX: 180,
offsetY: 180,
shape: {
type: 'Basic',
shape: 'RightTriangle',
},
style: {
fill: '#6BA5D7',
},
},
{
id: 'group',
children: ['node1', 'node2',],
padding: { left: 20, right: 20, top: 20, bottom: 20 },
//Sets the flip as Horizontal
flip: FlipDirection.Horizontal,
}
];
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Group flip mode
The flipMode
property of a group node behaves similarly to that of normal nodes. However, when a flip mode is applied to a group node, it takes precedence over any flip mode set on its child nodes, overriding their individual settings.
Example of flip mode precedence:
In the code below, the flipMode
for the child node Node1
is set to LabelText
, while the flipMode
for the group node is set to Label
. The effective flipMode
for both the child node and the group node will be Label
, as the group node’s flipMode
overrides the child’s setting.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, DiagramModule, NodeModel, FlipDirection } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'node1',
width: 70,
height: 70,
offsetX: 100,
offsetY: 100,
//Sets the flip mode as LabelText
flipMode: 'LabelText',
annotations: [{ content: 'Node1', offset: { x: 0, y: 0.8 } }],
shape: {
type: 'Basic',
shape: 'RightTriangle',
},
style: {
fill: '#6BA5D7',
},
},
{
id: 'node2',
width: 70,
height: 70,
offsetX: 180,
offsetY: 180,
shape: {
type: 'Basic',
shape: 'RightTriangle',
},
style: {
fill: '#6BA5D7',
},
},
{
id: 'group',
children: ['node1', 'node2',],
padding: { left: 20, right: 20, top: 20, bottom: 20 },
annotations: [{ content: 'Group', offset: { x: 0, y: 0.8 } }],
//Sets the flip as Horizontal
flip: FlipDirection.Horizontal,
//Sets the flip mode as Label
flipMode: 'Label',
}
];
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Nested group
Nested groups are groups within groups, where a group can contain other groups as its children, creating a hierarchical structure. This feature helps manage complexity and relationships between different elements in sophisticated diagram scenarios.
The following code illustrates how to create nested group nodes:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, DiagramModule, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [ ],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'node1',
width: 100,
height: 100,
offsetX: 100,
offsetY: 100,
annotations: [{ content: 'Node1' }],
},
{
id: 'node2',
width: 100,
height: 100,
offsetX: 200,
offsetY: 200,
annotations: [{ content: 'Node2' }],
},
{
id: 'node3',
width: 100,
height: 100,
offsetX: 300,
offsetY: 350,
annotations: [{ content: 'Node3' }],
},
{
id: 'node4',
width: 100,
height: 100,
offsetX: 500,
offsetY: 350,
annotations: [{ content: 'Node4' }],
},
{
id: 'group1',
children: ['node1', 'node2'],
padding: { left: 20, right: 20, top: 20, bottom: 20 },
style: { fill: 'green' },
},
{
id: 'group2',
children: ['node3', 'node4'],
padding: { left: 20, right: 20, top: 20, bottom: 20 },
style: { fill: 'skyblue' },
},
// Nested Group
{
id: 'group3',
children: ['group1', 'group2'],
padding: { left: 20, right: 20, top: 20, bottom: 20 },
style: { fill: 'yellow' },
}
];
public created(args: Object): void {
(this.diagram as DiagramComponent).select([(this.diagram as DiagramComponent).getObject('group3')]);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Add groups to symbol palette
Group nodes can be added to the symbol palette like normal nodes, enabling reusable group templates for consistent diagram creation. This feature allows developers to create standardized group configurations that can be dragged and dropped into diagrams.
The following code illustrates how to render group nodes in the palette:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, SymbolPaletteModule, DiagramComponent, NodeModel, PaletteModel, SymbolPaletteComponent } from '@syncfusion/ej2-angular-diagrams';
import { ExpandMode } from '@syncfusion/ej2-navigations';
@Component({
imports: [
DiagramModule, SymbolPaletteModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-symbolpalette #symbolpalette id="symbolpalette" [expandMode]="expandMode" width="30%" [palettes]="palettes" >
</ejs-symbolpalette>
<ejs-diagram #diagram id="diagram" width="70%" height="645px" [nodes]='nodes' (created)='created($event)'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
@ViewChild("symbolpalette")
public symbolPalette?: SymbolPaletteComponent;
public expandMode: ExpandMode = 'Multiple';
public nodes: NodeModel[] = [
{
offsetX: 250,
offsetY: 250,
width: 100,
height: 100,
visible: true,
style: { fill: '#6AA8D7', strokeWidth: 1 },
}
];
getSymbols(): NodeModel[] {
let shapes: NodeModel[] = [
{
id: 'n1',
height: 50,
width: 50,
offsetX: 50,
offsetY: 50,
style: { fill: 'green' },
},
{
id: 'n2',
height: 50,
width: 50,
offsetX: 100,
offsetY: 100,
style: { fill: 'yellow' },
},
{
id: 'group1',
children: ['n1', 'n2'],
padding: { left: 10, right: 10, top: 10, bottom: 10 },
},
{
id: 'n3',
height: 50,
width: 50,
offsetX: 100,
offsetY: 100,
style: { fill: 'pink' },
},
{
id: 'n4',
height: 50,
width: 50,
offsetX: 100,
offsetY: 170,
style: { fill: 'orange' },
},
{
id: 'group2',
children: ['n3', 'n4'],
padding: { left: 10, right: 10, top: 10, bottom: 10 },
},
];
return shapes;
}
public palettes: PaletteModel[] = [
{
id: 'palette1',
title: 'Basic Shapes',
symbols: this.getSymbols(),
expanded: true,
}
]
public created(args: Object): void {
(this.diagram as DiagramComponent).fitToPage({ mode: 'Width' });
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Update group nodes at runtime
Groups can be updated dynamically similar to normal nodes, allowing modification of group properties, styling, and behavior during runtime operations.
The following code illustrates how to update group nodes at runtime:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<button (click)="updatePadding()">updateGroupPadding</button>
<button (click)="updateStyle()">updateGroupStyle</button>
<ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]='nodes'>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public nodes: NodeModel[] = [
{
id: 'rectangle1',
offsetX: 100,
offsetY: 100,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle1',
},
],
},
{
id: 'rectangle2',
offsetX: 200,
offsetY: 200,
width: 100,
height: 100,
style: {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
},
annotations: [
{
content: 'rectangle2',
},
],
},
{
id: 'group',
children: ['rectangle1', 'rectangle2'],
style: { strokeColor: 'green' },
},
];
updatePadding() {
let group: NodeModel = (this.diagram as DiagramComponent).getObject('group');
(group.padding = { left: 10, right: 10, top: 10, bottom: 10 }), group.style;
(this.diagram as DiagramComponent).dataBind();
}
updateStyle() {
let group: NodeModel = (this.diagram as DiagramComponent).getObject('group');
group.style = { fill: 'green' };
(this.diagram as DiagramComponent).dataBind();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Container types
Containers provide automatic measurement and arrangement of child element size and position according to predefined layout behaviors. The diagram supports two container types, each optimized for different layout scenarios.
Canvas container
The canvas panel supports absolute positioning and provides minimal layout functionality to its contained diagram elements. This container type offers maximum flexibility for precise element placement.
Canvas container characteristics:
- Supports absolute positioning using margin and alignment properties
- Enables rendering operations independently for each contained element
- Allows elements to be aligned vertically or horizontally
- Child elements are defined using the
canvas.children
property - Basic elements can be defined within the
basicElements
collection
Stack container
The stack panel arranges its children in a single line or stack order, either vertically or horizontally. This container provides structured layout control through spacing and alignment properties.
Stack container characteristics:
- Controls spacing using margin properties of child elements and padding properties of the group
- Default
orientation
is vertical - Provides consistent alignment and distribution of child elements
- Ideal for creating organized, sequential layouts
The following code illustrates how to add a stack panel:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, Diagram, NodeModel, TextElement, StackPanel, PointModel, VerticalAlignment, ShapeStyleModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults' [setNodeTemplate]="setNodeTemplate">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100>
<e-node-annotations>
<e-node-annotation content="Custom Template" [offset]='offset' [verticalAlignment]='verticalAlignment'>
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public offset?: PointModel = { y: 1 };
public verticalAlignment?: VerticalAlignment = 'Top';
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
((node as NodeModel).style as ShapeStyleModel).fill = '#6BA5D7';
((node as NodeModel).style as ShapeStyleModel).strokeColor = 'white';
return node;
}
public setNodeTemplate(obj: NodeModel | any, diagram: Diagram): StackPanel | undefined {
if (obj.id.indexOf('node1') !== -1) {
let table: StackPanel = new StackPanel();
table.orientation = 'Horizontal';
// stack panel - column 1
let column1: StackPanel = new StackPanel();
column1.children = [];
// add coloumn 1 text element
let textElement1: TextElement = new TextElement();
textElement1.width = 50;
textElement1.height = 20;
textElement1.content = 'Column1';
column1.children.push(textElement1);
// row 1
let row11: TextElement = new TextElement();
row11.width = 50;
row11.height = 20;
row11.content = 'Row1';
column1.children.push(row11);
// row 2
let row12: TextElement = new TextElement();
row12.width = 50;
row12.height = 20;
row12.content = 'Row2';
column1.children.push(row12);
//row 3
let row13: TextElement = new TextElement();
row13.width = 50;
row13.height = 20;
row13.content = 'Row3';
column1.children.push(row13);
// row 4
let row14: TextElement = new TextElement();
row14.width = 50;
row14.height = 20;
row14.content = 'Row4';
column1.children.push(row14);
// stack panel - column 2
let column2: StackPanel = new StackPanel();
column2.children = [];
// add coloumn 2 text element
let textElement2: TextElement = new TextElement();
textElement2.width = 50;
textElement2.height = 20;
textElement2.content = 'Column2';
column2.children.push(textElement2);
// row 1
let row21: TextElement = new TextElement();
row21.width = 50;
row21.height = 20;
row21.content = 'Row1';
column2.children.push(row21);
// row 2
let row22: TextElement = new TextElement();
row22.width = 50;
row22.height = 20;
row22.content = 'Row2';
column2.children.push(row22);
// row 3
let row23: TextElement = new TextElement();
row23.width = 50;
row23.height = 20;
row23.content = 'Row3';
column2.children.push(row23);
// row 4
let row24: TextElement = new TextElement();
row24.width = 50;
row24.height = 20;
row24.content = 'Row4';
column2.children.push(row24);
// add both the coloumn stack panel as children of a horizontal stack panel
table.children = [column1, column2];
return table;
}
return undefined;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Difference between basic groups and containers
Basic Group | Container |
---|---|
Arranges child elements based on the child elements’ position and size properties | Each container has predefined behavior to measure and arrange child elements. Canvas and stack containers are supported in the diagram |
The padding, minimum, and maximum size properties are not applicable for basic groups | These properties are applicable for containers |
The children’s margin and alignment properties are not applicable for basic groups | These properties are applicable for containers |
Group interactions
Group node interactions can be performed similarly to normal nodes. Fundamental diagram interactions like selecting, dragging, resizing, and rotating apply equally to group nodes. For more information, refer to the node interactions documentation.
Selecting group nodes
When a child element within a node group is clicked, the entire containing node group is selected instead of the individual child element. Subsequent clicks on the selected element change the selection from top to bottom within the hierarchy, moving from the parent node group to its children.
Events
The events triggered when interacting with group nodes are similar to those for individual nodes. For more information, refer to the node events documentation.