User handle in Angular Diagram component
28 Mar 202324 minutes to read
- User handles are used to add some frequently used commands around the selector. To create user handles, define and add them to the
userHandles
collection of theselectedItems
property. - The name property of user handle is used to define the name of the user handle and its further used to find the user handle at runtime and do any customization.
Alignment
User handles can be aligned relative to the node boundaries. It has margin
, offset
, side
, horizontalAlignment
, and verticalAlignment
settings. It is quite tricky when all four alignments are used together but gives more control over alignment.
Offset for user handle
The offset
property of userHandles
is used to align the user handle based on fractions. 0 represents top/left corner, 1 represents bottom/right corner, and 0.5 represents half of width/height.
Side
The side
property of userHandles
is used to align the user handle by using the Top
, Bottom
, Left
, and Right
options.
Horizontal and vertical alignments
The horizontalAlignment
property of userHandles
is used to set how the user handle is horizontally aligned at the position based on the offset
. The verticalAlignment
property is used to set how user handle is vertically aligned at the position.
Margin for user handle
Margin is an absolute value used to add some blank space in any one of its four sides. The userHandles
can be displaced with the margin
property.
Appearance
The appearance of the user handle can be customized by using the size
, borderColor
, backgroundColor
, visible
, pathData
, and pathColor
properties of the userHandles
.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramComponent, SelectorModel, IElement, randomId, cloneObject, UserHandleModel, SelectorConstraints, ToolBase, NodeModel, Diagram, MoveTool } from '@syncfusion/ej2-angular-diagrams';
@Component({
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults]='getNodeDefaults' [getCustomTool]='getCustomTool' [selectedItems]='selectedItems'>
<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 handles: UserHandleModel[] = [
{
name: "clone",
pathData: "M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5, 28.9h-30c-3, 0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z",
visible: true,
offset: 0,
side: "Bottom",
margin: { top: 0, bottom: 0, left: 0, right: 0 }
}
];
public selectedItems: SelectorModel = {
constraints: SelectorConstraints.UserHandle,
userHandles: this.handles
};
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
node.style.fill = "#6BA5D7";
node.style.strokeColor = "#6BA5D7";
return node;
}
public getCustomTool: Function = this.getTool.bind(this);
public getTool(action: string): ToolBase {
let tool: ToolBase;
if (action === "clone") {
let cloneTool: CloneTool = new CloneTool(this.diagram.commandHandler);
cloneTool.diagram = this.diagram;
return cloneTool;
}
return tool;
}
}
//Defines the clone tool used to copy Node/Connector.
class CloneTool extends MoveTool {
public diagram: Diagram = null;
public mouseDown(args: MouseEventArgs): void {
let newObject: NodeModel | ConnectorModel;
if (this.diagram.selectedItems.nodes.length > 0) {
newObject = cloneObject(this.diagram.selectedItems.nodes[0]) as NodeModel;
} else {
newObject = cloneObject(this.diagram.selectedItems.connectors[0]) as ConnectorModel;
}
newObject.id += randomId();
this.diagram.paste([newObject]);
args.source = this.diagram.nodes[this.diagram.nodes.length - 1] as IElement;
args.sourceWrapper = args.source.wrapper;
super.mouseDown(args);
this.inAction = true;
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule, DiagramModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [ ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Fixed user handles
Fixed user handles are used to add some frequently used commands around the node and connector even without selecting it.
Initialization an fixed user handles
To create fixed user handles, define and add them to the collection of nodes and connectors property. The following code example used to create an fixed user handles for the nodes/connectors.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
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-fixeduserhandles>
<e-node-fixeduserhandle [margin]='margin1' pathData='M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5,28.9h-30c-3,0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z'>
</e-node-fixeduserhandle>
</e-node-fixeduserhandles>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public margin1: MarginModel;
ngOnInit(): void {
this.margin1 = { right: 20 };
}
public diagram: DiagramComponent;
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
node.style.fill = "#6BA5D7";
node.style.strokeColor = "White";
return node;
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule, DiagramModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [ ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Customization
-
The id property of fixed user handle is used to define the unique identification of the fixed user handle and its further used to add custom events to the fixed user handle.
-
The fixed user handle can be positioned relative to the node and connector boundaries. It has offset, padding and cornerRadius settings. It is used to position and customize the fixed user handle.
-
The
Padding
is used to leave the space that’s inside the fixed user handle between the icon and the border. -
Corner radius allows to create fixed user handles with rounded corners. The radius of the rounded corner is set with the
cornerRadius
property.
Note: PathData should need to be provided to render fixed user handle.
Size
Diagram allows you set size for fixed user handles by using the width
and height
property. The default value of the width and height property is 10.
Style
-
You can change the style of the fixed user handles with the specific properties of borderColor, borderWidth, and background color using handleStrokeColor, handleStrokeWidth, and fill properties and the icon borderColor and borderWidth using iconStrokeColor and iconStrokeWidth.
-
The fixed user handle’s
iconStrokeColor
andiconStrokeWidth
property used to change the stroke color and stroke width of the givenpathData
. -
The fixed user handle
handleStrokeColor
,fill
properties are used to define the background color and border color of the userhandle and thehandleStrokeWidth
property is used to define the border width of the fixed user handle. -
The
visible
property of the fixed user handle enables or disables the visibility of fixed user handle.
The following code explains how to customize the appearance of the fixed user handles.
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel, ConnectorModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults' [getConnectorDefaults] ='getConnectorDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150>
<e-node-fixeduserhandles>
<e-node-fixeduserhandle [width]=20 [height]=20 iconStrokeColor='white' fill='black' [margin]='margin1' [padding]='padding1' pathData='M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5,28.9h-30c-3,0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z'>
</e-node-fixeduserhandle>
</e-node-fixeduserhandles>
</e-node>
</e-nodes>
<e-connectors>
<e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint1' [targetPoint]='targetPoint1'>
<e-connector-fixeduserhandles>
<e-connector-fixeduserhandle iconStrokeColor='white' [padding]='padding1' fill='black' [width]=20 [height]=20 pathData='M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5,28.9h-30c-3,0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z'>
</e-connector-fixeduserhandle>
</e-connector-fixeduserhandles>
</e-connector>
</e-connectors>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram: DiagramComponent;
public sourcePoint1: PointModel;
public margin1: MarginModel;
public padding1: MarginModel;
ngOnInit(): void {
this.sourcePoint1 = { x: 300, y: 100 };
this.targetPoint1 = { x: 400, y: 200 };
this.margin1 = { right: 20 };
this.padding1 = { left: 2, right: 2, top: 2, bottom:2 };
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
node.style.fill = "#6BA5D7";
node.style.strokeColor = "White";
return node;
}
public getConnectorDefaults(obj: ConnectorModel): ConnectorModel {
obj.style = {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
strokeWidth: 2
}
obj.targetDecorator = {
style: {
fill: '#6BA5D7',
strokeColor: '#6BA5D7'
}
}
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule, DiagramModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [ ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Note: Fixed user handle id should need to be unique.
Customizing node fixed user handle
The node fixed user handle can be aligned relative to the node boundaries. It has margin
and offset
settings. It is quite useful to position the node fixed userhandle and used together and gives you more control over the node fixed user handle positioning.
Margin for node fixed user handle
Margin is an absolute value used to add some blank space in any one of its four sides. The fixed user handle can be displaced with the margin
property.
Offset for node fixed user handle
The offset
property of fixed user handle is used to align the user handle based on x
and y
points. (0,0) represents top/left corner and (1,1) represents bottom/right corner.
The following table shows all the possible alignments visually shows the fixed user handle positions.
Offset | Margin | Output |
---|---|---|
(0,0) | Right = 20 | ![]() |
(0.5,0) | Bottom = 20 | ![]() |
(1,0) | Left = 20 | ![]() |
(0,0.5) | Right = 20 | ![]() |
(0,1) | Left = 20 | ![]() |
(0,1) | Right = 20 | ![]() |
(0.5,1) | Top = 20 | ![]() |
(1,1) | Left = 20 | ![]() |
The following code explains how to customize the node fixed user handle.
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
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-fixeduserhandles>
<e-node-fixeduserhandle [width]=20 [height]=20 [margin]='margin1' pathData='M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5,28.9h-30c-3,0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z'>
</e-node-fixeduserhandle>
</e-node-fixeduserhandles>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public margin1: MarginModel;
ngOnInit(): void {
this.margin1 = { right: 20 };
}
public diagram: DiagramComponent;
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
node.style.fill = "#6BA5D7";
node.style.strokeColor = "White";
return node;
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule, DiagramModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [ ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);
Customizing connector fixed user handle
-
The connector fixed user handle can be aligned relative to the connector boundaries. It has alignment, displacement and offset settings. It is useful to position the connector fixed userhandle and used together and gives you more control over the connector fixed user handle positioning.
-
The
offset
andalignment
properties of fixed user handle allows you to align the connector fixed user handles with respect to the segments.
Offset for connector fixed user handle
The offset
property of connector fixed user handle is used to align the user handle based on fractions. 0 represents the connector source point, 1 represents the connector target point, and 0.5 represents the center point of the connector segment.
Alignment
The connector’s fixed user handle can be aligned over its segment path using the alignment
property of fixed user handle.
The following table shows all the possible alignments visually shows the fixed user handle positions.
Offset | Alignment | Output |
---|---|---|
0 | Before | ![]() |
0.5 | Center | ![]() |
1 | After | ![]() |
Displacement
The displacement
property allows you to specify the space to be left from the connector segment based on the x and y value provided.
The following table shows all the possible alignments visually shows the fixed user handle positions.
Displacment | Alignment | Output |
---|---|---|
x=10 | Before | ![]() |
x=10 | After | ![]() |
y=10 | Before | ![]() |
y=10 | After | ![]() |
Note: Displacement will not be done if the alignment is set to be center.
The following code explains how to customize the connector fixed user handle.
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, ConnectorModel } from '@syncfusion/ej2-angular-diagrams';
@Component({
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getConnectorDefaults] ='getConnectorDefaults'>
<e-connectors>
<e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint1' [targetPoint]='targetPoint1'>
<e-connector-fixeduserhandles>
<e-connector-fixeduserhandle [width]=20 [height]=20 pathData='M60.3,18H27.5c-3,0-5.5,2.4-5.5,5.5v38.2h5.5V23.5h32.7V18z M68.5,28.9h-30c-3,0-5.5,2.4-5.5,5.5v38.2c0,3,2.4,5.5,5.5,5.5h30c3,0,5.5-2.4,5.5-5.5V34.4C73.9,31.4,71.5,28.9,68.5,28.9z M68.5,72.5h-30V34.4h30V72.5z'>
</e-connector-fixeduserhandle>
</e-connector-fixeduserhandles>
</e-connector>
</e-connectors>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram: DiagramComponent;
public sourcePoint1: PointModel;
ngOnInit(): void {
this.sourcePoint1 = { x: 300, y: 100 };
this.targetPoint1 = { x: 400, y: 200 };
}
public getConnectorDefaults(obj: ConnectorModel): ConnectorModel {
obj.style = {
strokeColor: '#6BA5D7',
fill: '#6BA5D7',
strokeWidth: 2
}
obj.targetDecorator = {
style: {
fill: '#6BA5D7',
strokeColor: '#6BA5D7'
}
}
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DiagramModule } from '@syncfusion/ej2-angular-diagrams';
/**
* Module
*/
@NgModule({
imports: [
BrowserModule, DiagramModule
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [ ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);