Nodes in Angular Diagram Component
29 Aug 202522 minutes to read
Nodes are graphical objects that visually represent entities, processes, data flow, or any business logic within diagrams. They serve as the fundamental building blocks for creating flowcharts, organizational charts, network diagrams, and other visual representations. Each node can be customized with different shapes, sizes, colors, and interactive behaviors to suit specific diagram requirements.
Node fundamentals
Before creating nodes, understanding their core properties helps in effective diagram development:
-
Position: Defined by
offsetX
andoffsetY
properties for precise placement -
Size: Controlled through
width
andheight
properties -
Identification: Each node requires a unique
id
for runtime operations - Stacking: Nodes are layered from bottom to top based on addition order
Creating nodes
Add nodes through nodes collection
To create a node, define the node
object and add it to the nodes
collection of the diagram model. The id
property serves as the unique identifier for runtime operations and customization.
import {
DiagramModule,
DiagramComponent,
NodeModel,
ShapeStyleModel,
} from '@syncfusion/ej2-angular-diagrams';
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [DiagramModule],
providers: [],
standalone: true,
selector: 'app-container',
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None,
})
export class AppComponent {
@ViewChild('diagram')
public diagram?: DiagramComponent;
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
NOTE
Node ID must begin with a letter, remain unique across all shapes and connectors, and avoid whitespace or special characters.
Create nodes from data source
Nodes can be generated automatically using the dataSource property. Default properties for these nodes are retrieved from getNodeDefaults
settings. For detailed information about data binding, refer to DataBinding.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import {
DataSourceModel,
DiagramComponent,
DiagramModule,
Diagram,
NodeModel,
DataBinding,
} from '@syncfusion/ej2-angular-diagrams';
import { DataManager, Query } from '@syncfusion/ej2-data';
Diagram.Inject(DataBinding);
@Component({
imports: [DiagramModule],
providers: [],
standalone: true,
selector: 'app-container',
template: `<ejs-diagram #diagram id="diagram" width="100%" height="1000px" [getNodeDefaults] ='getNodeDefaults' [dataSourceSettings]="dataSourceSettings">
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None,
})
export class AppComponent {
@ViewChild('diagram')
public diagram?: DiagramComponent;
public dataSourceSettings?: DataSourceModel;
public items?: DataManager;
public data: Object[] = [
{
id: 'Steve-Ceo',
parent: null,
},
];
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
node.offsetX = 300;
node.offsetY = 200;
node.style = { fill: 'yellow', strokeColor: 'yellow' };
return node;
}
ngOnInit(): void {
this.items = new DataManager(this.data as JSON[], new Query().take(7));
this.dataSourceSettings = {
id: 'id',
parentId: 'parent',
dataSource: this.items,
};
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Add nodes from symbol palette
Nodes can be predefined in a symbol palette and dragged into the diagram as needed. This approach provides users with a library of reusable components. For comprehensive guidance on symbol palette integration, refer to Symbol Palette.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import {
DiagramComponent,
DiagramModule,
ShapeStyleModel,
SymbolPaletteModule,
NodeModel,
PaletteModel,
} from '@syncfusion/ej2-angular-diagrams';
@Component({
imports: [DiagramModule, SymbolPaletteModule],
providers: [],
standalone: true,
selector: 'app-container',
template: `
<ejs-symbolpalette id="symbolpalette"width="10%" height="700px" [palettes]="palettes" [symbolHeight]=80 [symbolWidth]=80 >
</ejs-symbolpalette>
<ejs-diagram #diagram id="diagram" width="74%" height="700px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None,
styles: [
`
ejs-symbolpalette {
float: left;
}
`,
],
})
export class AppComponent {
@ViewChild('diagram')
public diagram?: DiagramComponent;
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
public palettes?: PaletteModel[];
public getBasicShapes(): NodeModel[] {
let basicShapes: NodeModel[] = [
{
id: 'Rectangle',
shape: {
type: 'Basic',
shape: 'Rectangle',
},
style: { fill: '#6BA5D7' },
},
];
return basicShapes;
}
ngOnInit(): void {
this.palettes = [
{
id: 'basic',
expanded: true,
symbols: this.getBasicShapes(),
title: 'Basic Shapes',
iconCss: 'e-ddb-icons e-basic',
},
];
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Draw nodes interactively
To enable interactive node drawing, activate the drawing tool by setting DrawOnce
or ContinuousDraw
to the tool
property and configure the node template using the drawingObject
property.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import {
DiagramModule,
DiagramComponent,
Diagram,
NodeModel,
BasicShapeModel,
DiagramTools,
} 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 drawingshape?: BasicShapeModel;
public node?: NodeModel;
public created(args: Object): void {
//JSON to create a rectangle
this.drawingshape = { type: 'Basic', shape: 'Rectangle' };
this.node = {
shape: this.drawingshape,
};
(this.diagram as Diagram).drawingObject = this.node;
//To draw an object once, activate draw once
(this.diagram as Diagram).tool = DiagramTools.DrawOnce;
(this.diagram as Diagram).dataBind();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Runtime node operations
Add and remove individual nodes
Nodes can be dynamically added using the add
method and removed using the remove
method. Both operations trigger the collectionChange
event, allowing for custom handling of diagram modifications.
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, 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 node: NodeModel = {
// Position of the node
offsetX: 250,
offsetY: 250,
// Size of the node
width: 100,
height: 100,
style: {
fill: '#6BA5D7',
strokeColor: 'white'
},
};
public created(args: Object): void {
//Add Node
(this.diagram as Diagram).add(this.node);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Add multiple nodes simultaneously
Collections of nodes can be efficiently added using the addElements
method. This approach is optimal for bulk operations and triggers the collectionChange
event for each added element.
import { DiagramModule, DiagramComponent, Diagram, NodeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@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 node: NodeModel =[
{ id: 'node16', offsetX: 35, offsetY: 260 },
{ id: 'node17', offsetX: 140, offsetY: 260 },
{ id: 'node18', offsetX: 240, offsetY: 260 }] as NodeModel;
public created(args: Object): void {
//Add Nodes collection
(this.diagram as Diagram).addElements(this.node as any);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Update node properties
Node properties can be modified at runtime with immediate visual updates. Changes take effect instantly, allowing for dynamic diagram manipulation based on user interactions or data updates.
import {
DiagramModule,
ShapeStyleModel,
DiagramComponent,
Diagram,
NodeModel,
} from '@syncfusion/ej2-angular-diagrams';
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [DiagramModule],
providers: [],
standalone: true,
selector: 'app-container',
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [nodes]="nodes" >
</ejs-diagram>
<button (click) = "ChangeColor()">Change Color</button>
<button (click) = "ChangeSize()">Change Size</button>`,
styles: [
`button {
margin-left: 10px;
}`,
],
encapsulation: ViewEncapsulation.None,
})
export class AppComponent {
public nodes: NodeModel[] = [
{
id: 'node1',
offsetX: 420,
offsetY: 270,
height: 100,
width: 100,
style: { fill: '#6AA8D7', strokeWidth: 1 },
},
];
@ViewChild('diagram')
public diagram?: DiagramComponent;
ChangeColor() {
if (
((this.diagram as Diagram).nodes[0].style as ShapeStyleModel).fill ==
'orange'
) {
((this.diagram as Diagram).nodes[0].style as ShapeStyleModel).fill =
'#6AA8D7';
} else {
((this.diagram as Diagram).nodes[0].style as ShapeStyleModel).fill =
'orange';
}
}
ChangeSize() {
if (
(this.diagram as Diagram).nodes[0].width == 200 &&
(this.diagram as Diagram).nodes[0].height == 200
) {
(this.diagram as Diagram).nodes[0].width = 100;
(this.diagram as Diagram).nodes[0].height = 100;
} else {
(this.diagram as Diagram).nodes[0].width = 200;
(this.diagram as Diagram).nodes[0].height = 200;
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
NOTE
Call the
dataBind
method after property updates to ensure immediate reflection of changes.
Clone nodes
Node cloning creates new instances with identical properties and attributes. Use the copy
and paste
methods to duplicate existing nodes programmatically.
import {
DiagramModule,
DiagramComponent,
NodeModel,
} from '@syncfusion/ej2-angular-diagrams';
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [DiagramModule],
providers: [],
standalone: true,
selector: 'app-container',
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [nodes]="nodes" >
</ejs-diagram>
<button (click) = "CloneNode()">Clone Node</button>`,
styles: [
`button {
margin-left: 10px;
}`,
],
encapsulation: ViewEncapsulation.None,
})
export class AppComponent {
public nodes: NodeModel[] = [
{
id: 'node1',
offsetX: 420,
offsetY: 270,
height: 100,
width: 100,
style: { fill: '#6AA8D7', strokeWidth: 1 },
},
];
@ViewChild('diagram')
public diagram?: DiagramComponent;
public selectedNode?: NodeModel;
CloneNode() {
this.selectedNode =
((this.diagram as DiagramComponent).selectedItems.nodes
?.length as number) > 0
? (
(this.diagram as DiagramComponent).selectedItems
.nodes as NodeModel[]
)[0]
: (this.diagram as DiagramComponent).nodes[0];
(this.diagram as DiagramComponent).select([this.selectedNode]);
(this.diagram as DiagramComponent).copy();
(this.diagram as DiagramComponent).paste();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Advanced node integration
Import nodes from external components
Custom dragEnter
functionality enables conversion of elements from other components, such as tree views, into diagram nodes based on the dragged element’s data properties.