Interactive Port Features in Angular Diagram Component

29 Aug 202524 minutes to read

Ports in Angular Diagram components support various interactive features that enhance user workflow and diagram creation efficiency. This guide covers drawing connectors from ports, drag functionality, automatic port creation, tooltips, and event handling.

Draw connector from port

Ports can serve as connection points for creating connectors dynamically. Enable the Draw constraint on the constraints property to allow users to draw connectors directly from ports. The default connector segment type is Orthogonal, providing structured, right-angled connections suitable for flowcharts and organizational diagrams.

This feature is particularly useful in scenarios where users need to create connections interactively, such as building workflow diagrams or network topologies.

import {  Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, PointPortModel, PortVisibility,PortConstraints, PointModel, PathPortModel } from '@syncfusion/ej2-angular-diagrams';

@Component({
imports: [
         DiagramModule
    ],
providers: [ ],
standalone: true,
  selector: "app-container",
  // specifies the template string for the diagram component
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px">
        <e-nodes>
            <e-node id='node1' [offsetX]=250 [offsetY]=250 [width]=100 [height]=100 [ports]='ports'></e-node>
        </e-nodes>
        <e-connectors>
            <e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint' [targetPoint]='targetPoint' [ports]='ports1'>
            </e-connector>
        </e-connectors>
    </ejs-diagram>`,
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public sourcePoint?: PointModel;
    public targetPoint?: PointModel;
    
    ngOnInit(): void {
        this.sourcePoint = { x: 100, y: 100 };
        this.targetPoint = { x: 300, y: 120 };
    }
    
    public ports: PointPortModel[] = [
        {
            offset: {
                x: 1,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Draw,
        },
    ]
    public ports1: PathPortModel[] = [
        {
           offset: 0.5,
           visibility: PortVisibility.Visible,
           constraints: PortConstraints.Default | PortConstraints.Draw,
        },
    ]

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

Draw different connector types from port

The default connector type can be customized when drawing from ports by configuring connector defaults. This flexibility allows creation of various connector styles to match different diagram requirements:

  • Straight: Direct linear connections for simple relationships
  • Bezier: Curved connections for organic, flowing designs
  • Orthogonal: Right-angled connections for structured layouts
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, ConnectorModel, PointPortModel, PortVisibility,PortConstraints, PointModel, PathPortModel } from '@syncfusion/ej2-angular-diagrams';

@Component({
imports: [
         DiagramModule
    ],
providers: [ ],
standalone: true,
  selector: "app-container",
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getConnectorDefaults]='getConnectorDefaults'>
        <e-nodes>
            <e-node id='node1' [offsetX]=250 [offsetY]=250 [width]=100 [height]=100 [ports]='ports'></e-node>
        </e-nodes>
        <e-connectors>
            <e-connector id='connector' [sourcePoint]='sourcePoint' [targetPoint]='targetPoint' [ports]='ports1'>
            </e-connector>
        </e-connectors>
    </ejs-diagram>`,
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public sourcePoint?: PointModel;
    public targetPoint?: PointModel;

    ngOnInit(): void {
        this.sourcePoint = { x: 100, y: 100 };
        this.targetPoint = { x: 300, y: 120 };
    }
    
    public ports: PointPortModel[] = [
        {
            offset: {
                x: 1,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Draw,
        },
    ]
    public ports1: PathPortModel[] = [
        {
           offset: 0.5,
           visibility: PortVisibility.Visible,
           constraints: PortConstraints.Default | PortConstraints.Draw,
        },
    ]

    public getConnectorDefaults(connector: ConnectorModel): ConnectorModel {
        connector.type = 'Bezier';
        return connector;
    }

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

Port drag

Port drag functionality enables users to reposition ports by clicking and dragging with the mouse. This feature enhances diagram flexibility by allowing dynamic port placement adjustments. Enable this capability by setting the port constraints to Drag.

Port dragging is valuable when fine-tuning diagram layouts or adapting to changing connection requirements without recreating elements.

import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, PointPortModel, PortVisibility,PortConstraints, PointModel, PathPortModel } from '@syncfusion/ej2-angular-diagrams';

@Component({
imports: [
         DiagramModule
    ],
providers: [ ],
standalone: true,
  selector: "app-container",
  // specifies the template string for the diagram component
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px">
        <e-nodes>
            <e-node id='node1' [offsetX]=250 [offsetY]=250 [width]=100 [height]=100 [ports]='ports'>
                <e-node-annotations>
                    <e-node-annotation content="Click and drag the port">
                    </e-node-annotation>
                </e-node-annotations>
            </e-node>
        </e-nodes>
        <e-connectors>
            <e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint' [targetPoint]='targetPoint' [ports]='ports1'>
            </e-connector>
        </e-connectors>
    </ejs-diagram>`,
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public sourcePoint?: PointModel;
    public targetPoint?: PointModel;
    ngOnInit(): void {
        this.sourcePoint = { x: 100, y: 100 };
        this.targetPoint = { x: 300, y: 120 };
    }
    
    public ports: PointPortModel[] = [
        {
            offset: {
                x: 1,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Drag,
        },
    ]
    public ports1: PathPortModel[] = [
        {
           offset: 0.5,
           visibility: PortVisibility.Visible,
           constraints: PortConstraints.Default | PortConstraints.Drag,
        },
    ]

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

Automatic Port Creation

The Diagram component supports dynamic port creation through user interaction. Users can create ports on nodes or connectors by clicking and dragging while holding the Control (Ctrl) key. This feature is disabled by default and requires enabling the DiagramConstraints.AutomaticPortCreation constraint.

Ports can also be removed using the same Ctrl + Click interaction, provided the port is not connected to any connector. This prevents accidental disconnection of active connections.

import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import {
    DiagramModule, DiagramComponent, NodeModel, DiagramConstraints,
    NodeConstraints, SnapConstraints, SnapSettingsModel
} from '@syncfusion/ej2-angular-diagrams';

@Component({
    imports: [DiagramModule],
    providers: [],
    standalone: true,
    selector: "app-container",
    // specifies the template string for the diagram component with constraints
    template: `<ejs-diagram #diagram id="diagram" width="100%" height="500px" [nodes]='nodes'
                    [constraints]='diagramConstraints' [snapSettings]='snapSettings'>
               </ejs-diagram>`
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    // Enable AutomaticPortCreation
    public diagramConstraints: DiagramConstraints = DiagramConstraints.Default |
        DiagramConstraints.AutomaticPortCreation;
    public snapSettings: SnapSettingsModel = { constraints: SnapConstraints.None };
    public nodes: NodeModel[] = [
        {
            id: 'node1', width: 100, height: 100, offsetX: 150, offsetY: 200, style: { fill: 'cornflowerblue' },
            constraints: NodeConstraints.Default &
                ~(NodeConstraints.InConnect | NodeConstraints.OutConnect)

        },
        {
            id: 'node2', width: 100, height: 100, offsetX: 400, offsetY: 200, style: { fill: 'cornflowerblue' },
            constraints: NodeConstraints.Default &
                ~(NodeConstraints.InConnect | NodeConstraints.OutConnect)
        },
    ];
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Port tooltip

Port tooltips provide contextual information when users hover over ports, improving usability and user guidance. Enable this feature by setting the port constraints to Tooltip.

Tooltips are especially beneficial in complex diagrams where ports may not be immediately recognizable or when additional context helps users understand port functionality.

import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramModule, DiagramComponent, PointPortModel, PortVisibility,PortConstraints, PointModel, PathPortModel } from '@syncfusion/ej2-angular-diagrams';

@Component({
imports: [
         DiagramModule
    ],
providers: [ ],
standalone: true,
  selector: "app-container",
  // specifies the template string for the diagram component
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" >
        <e-nodes>
            <e-node id='node1' [offsetX]=250 [offsetY]=250 [width]=100 [height]=100 [ports]='ports'>
                <e-node-annotations>
                    <e-node-annotation content="Hover over port to see tooltip">
                    </e-node-annotation>
                </e-node-annotations>
            </e-node>
        </e-nodes>
        <e-connectors>
            <e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint' [targetPoint]='targetPoint' [ports]='ports1'>
            </e-connector>
        </e-connectors>
    </ejs-diagram>`,
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public sourcePoint?: PointModel;
    public targetPoint?: PointModel;

    ngOnInit(): void {
        this.sourcePoint = { x: 100, y: 100 };
        this.targetPoint = { x: 300, y: 120 };
    }
    
    public ports: PointPortModel[] = [
        {
            offset: {
                x: 1,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.ToolTip,
            tooltip: { content: 'node port tooltip' },
        },
    ]
    public ports1: PathPortModel[] = [
        {
           offset: 0.5,
           visibility: PortVisibility.Visible,
           constraints: PortConstraints.Default | PortConstraints.ToolTip,
           tooltip: { content: 'connector port tooltip' },
        },
    ]

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

Events

Port interactions trigger specific events that enable custom handling and application logic. These events provide hooks for implementing validation, logging, or custom behaviors during port operations.

Event Description Use Cases
Click Triggers when a port is clicked Custom selection logic, context menus
Element Draw Triggers when drawing a connector from a port Validation, custom connector properties
Position Change Triggers when a port is dragged Position validation, layout updates
Connection Change Triggers when a connector connects or disconnects from a port Relationship tracking, data validation
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { AnnotationAlignment, DiagramModule, DiagramComponent, PointPortModel, PortVisibility, PortConstraints, PointModel, PathPortModel, IClickEventArgs, IElementDrawEventArgs, IDraggingEventArgs, IConnectionChangeEventArgs, Connector } from '@syncfusion/ej2-angular-diagrams';

@Component({
imports: [
         DiagramModule
    ],
providers: [ ],
standalone: true,
  selector: "app-container",
  // specifies the template string for the diagram component
  template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" (click)="onClick($event)"
  (positionChange)="onPositionChange($event)"
  (connectionChange)="onConnectionChange($event)"
  (elementDraw)="onElementDraw($event)">
        <e-nodes>
            <e-node id='node1' [offsetX]=250 [offsetY]=250 [width]=100 [height]=100 [ports]='ports'>
                <e-node-annotations>
                    <e-node-annotation content="draw port" [offset]='offset1'>
                    </e-node-annotation>
                    <e-node-annotation content="darg port" [offset]='offset2'>
                    </e-node-annotation>
                </e-node-annotations>
            </e-node>
        </e-nodes>
        <e-connectors>
            <e-connector id='connector' type='Orthogonal' [sourcePoint]='sourcePoint' [targetPoint]='targetPoint' [ports]='ports1'>
                <e-connector-annotations>
                    <e-connector-annotation content='Draw port' [alignment] ='alignment' [displacement]='displacement'>
                    </e-connector-annotation>
                    <e-connector-annotation content='Drag port' [offset]= 0.7 [displacement]='displacement' [alignment] ='alignment'>
                    </e-connector-annotation>
                </e-connector-annotations>
            </e-connector>
        </e-connectors>
    </ejs-diagram>`,
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public sourcePoint?: PointModel;
    public targetPoint?: PointModel;
    public offset1?: PointModel;
    public offset2?: PointModel;
    public displacement?: PointModel;
    public alignment?: AnnotationAlignment;

    ngOnInit(): void {
        this.sourcePoint = { x: 100, y: 100 };
        this.targetPoint = { x: 300, y: 120 };
        this.offset1 = { x: 0, y: 0.7};
        this.offset2 = { x: 1, y: 0.7};
        this.displacement={x:0,y:10};
        this.alignment = 'After';
    }

    public ports: PointPortModel[] = [
        {
            id:'p1',
            offset: {
                x: 0,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Draw,
        },
        {
            id:'p2',
            offset: {
                x: 1,
                y: 0.5
            },
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Drag,
        },
    ]
    public ports1: PathPortModel[] = [
        {
           id:'p1',
           offset: 0.5,
           visibility: PortVisibility.Visible,
           constraints: PortConstraints.Default | PortConstraints.Draw,
        },
        {
            id:'p2',
            offset: 0.8,
            visibility: PortVisibility.Visible,
            constraints: PortConstraints.Default | PortConstraints.Drag,
         },
    ]
    
    public onClick(args: IClickEventArgs): void {
        console.log('clicked');
        // customize 
    }
    
    public onElementDraw(args: IElementDrawEventArgs): void {
        if (args.state === 'Start' && args.source instanceof Connector) {
          args.cancel = true; // Prevents connector drawing from connector port
        }
        // customize as needed
        console.log('Element draw event');
    }
    
    public onPositionChange(args: IDraggingEventArgs): void {
        console.log('Position change');
        // customize as needed
    }
    
    public onConnectionChange(args: IConnectionChangeEventArgs): void {
        console.log('Connection change');
        // customize as needed
    }


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

See also