Phase in Angular Diagram Component

Overview

Phases are subprocesses that split each lane horizontally or vertically based on the swimlane orientation. Phases help organize workflow stages within lanes, making it easier to visualize process steps and milestones. Multiple Phase objects can be added to a swimlane to represent different stages of a process.

The following code example illustrates how to create a phase.

import { Component, ViewEncapsulation, 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="580px" [nodes]="nodes">
    </ejs-diagram>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
      public nodes: NodeModel[] = [
        {
            id: 'swimlane',
            shape: {
                type: 'SwimLane',
                orientation: 'Horizontal',
                header: {
                    annotation: { content: 'ONLINE PURCHASE STATUS' },
                    height: 50, style: { fontSize: 11 },
                },
               lanes: [
                    {
                        id: 'stackCanvas1',
                        height: 100,
                        header: {
                            annotation: { content: 'CUSTOMER' }, width: 50,
                            style: { fontSize: 11 }
                        },
                          children: [
                            {
                                id: 'Order',
                                margin: { left: 60, top: 20 },
                                height: 40, width: 100
                            }
                        ],
                    },

                ],
               // Set phase to swimlane
             phases: [
                 {
                     id: 'phase1', offset: 120,
                     header: { annotation: { content: 'Phase' } }
                 },{
                    id: 'phase2', offset: 200,
                    header: { annotation: { content: 'Phase' } }
                },
                 ],
                phaseSize: 20,
            },
            offsetX: 420, offsetY: 270,
            height: 100,
            width: 650
        },
      ]
    @ViewChild("diagram")
    public diagram?: DiagramComponent;  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Dynamically add and remove phases from lanes

Phases can be added at runtime using the addPhases method and removed using the removePhase method. This dynamic functionality allows for flexible workflow management as process requirements change.

The following code example illustrates how to add and remove phases at runtime.

import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { DiagramComponent, Diagram, NodeModel,DiagramModule, ShapeModel } from '@syncfusion/ej2-angular-diagrams';

@Component({
    imports: [
        DiagramModule
    ],
    providers: [],
    standalone: true,
    selector: "app-container",
    template: `
        <button (click)="addPhase()">addPhase</button>
        <button (click)="removePhase()">removePhase</button>
        <ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]="nodes"></ejs-diagram>
       
    `,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    public nodes: NodeModel[] = [
        {
            id: 'swim1',
            shape: {
                type: 'SwimLane',
                orientation: 'Horizontal',
                header: {
                    annotation: {
                        content: 'ONLINE PURCHASE STATUS',
                    },
                    height: 50,
                    style: { fontSize: 11 },
                },
                lanes: [
                    {
                        id: 'stackCanvas1',
                        height: 100,
                        header: {
                            annotation: { content: 'CUSTOMER' },
                            width: 50,
                            style: { fontSize: 11 },
                        },
                    },
                ],
                phases: [
                    {
                        id: 'phase1',
                        offset: 120,
                        header: { annotation: { content: 'Phase' } },
                    },
                    {
                        id: 'phase2',
                        offset: 200,
                        header: { annotation: { content: 'Phase' } },
                    },
                ],
                phaseSize: 20,
            },
            offsetX: 300,
            offsetY: 200,
            height: 200,
            width: 350,
        },
    ];

    @ViewChild("diagram")
    public diagram?: DiagramComponent;

    public addPhase(): void {
        let swimlane = this.diagram?.getObject('swim1');
        const newPhase = [
            {
                id: 'phase3',
                offset: 250,
                header: { annotation: { content: 'New Phase' } },
            },
        ];
        if (swimlane) {
            /**
             * To add phases
             * parameter 1 - object representing the swimlane to which phases will be added.
             * parameter 2 - objects representing the phases to be added.
             */
            (this.diagram as Diagram).addPhases(swimlane, newPhase);
        }
    }

    public removePhase(): void {
        let swimlane:NodeModel = (this.diagram as Diagram).getObject('swim1');
        if (swimlane) {
            let phase = ((swimlane.shape) as ShapeModel | any).phases[
                ((swimlane.shape) as ShapeModel | any).phases.length - 1
            ];
            /**
             * To remove phase
             * parameter 1 - representing the swimlane to remove the phase from.
             * paramter 2 - representing the phase to be removed.
             */
            (this.diagram as Diagram).removePhase(swimlane, phase);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Customizing phase appearance and properties

Phase appearance and behavior can be customized through several properties:

  • The length of each region can be controlled using the offset property of the phase.
  • Each phase region can include descriptive text through the header property of the phase.
  • The height of phases can be increased using the phaseSize property of the swimlane.
  • Additional information can be stored with phases using the addInfo property of the phase.

The following code example illustrates how to customize phases in a swimlane.

import { Component, ViewEncapsulation, 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="580px" [nodes]="nodes">
    </ejs-diagram>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
      public nodes: NodeModel[] = [
        {
            id: 'swimlane',
            shape: {
                type: 'SwimLane',
                orientation: 'Horizontal',
                header: {
                    annotation: { content: 'ONLINE PURCHASE STATUS' },
                    height: 50, style: { fontSize: 11 },
                },
               lanes: [
                    {
                        id: 'stackCanvas1',
                        height: 100,
                        header: {
                            annotation: { content: 'CUSTOMER' }, width: 50,
                            style: { fontSize: 11 }
                        },
                    },

                ],
                phases: [
                    {
                      id: 'phase1',
                      offset: 150,
                      addInfo: { name: 'phase1' },
                      header: {
                        annotation: {
                          content: 'First phase',
                          style: { fill: 'yellow', color: 'red' },
                        },
                      },
                    },
                    {
                      id: 'phase2',
                      offset: 200,
                      header: { annotation: { content: 'Second phase' } },
                      style: { fill: 'violet' },
                    },
                  ],
                phaseSize: 20,
            },
            offsetX: 420, offsetY: 270,
            height: 100,
            width: 650
        },
      ]
    @ViewChild("diagram")
    public diagram?: DiagramComponent;  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Dynamic customization of phases

Phase style and text properties can be customized dynamically during runtime. This capability enables responsive design adjustments based on user interactions or changing data requirements.

The following code example illustrates how to customize phases at runtime.

import { DiagramModule, DiagramComponent, NodeModel, Diagram, ShapeModel } from '@syncfusion/ej2-angular-diagrams';
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';

@Component({
    imports: [
        DiagramModule
    ],
    providers: [],
    standalone: true,
    selector: "app-container",
    template: `
        <button (click)="updatePhase()">updatePhase</button>
        <ejs-diagram #diagram id="diagram" width="100%" height="600px" [nodes]="nodes"></ejs-diagram>
    `,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    public nodes: NodeModel[] = [
        {
            id: 'swimlane',
            shape: {
                type: 'SwimLane',
                orientation: 'Horizontal',
                header: {
                    annotation: {
                        content: 'ONLINE PURCHASE STATUS',
                    },
                    height: 50,
                    style: { fontSize: 11 },
                },
                lanes: [
                    {
                        id: 'stackCanvas1',
                        height: 100,
                        header: {
                            annotation: { content: 'CUSTOMER' },
                            width: 50,
                            style: { fontSize: 11 },
                        },
                    },
                ],
                phases: [
                    {
                        id: 'phase1',
                        offset: 150,
                        header: {
                            annotation: {
                                content: 'First phase',
                                style: { fill: 'yellow', color: 'red' },
                            },
                        },
                    },
                    {
                        id: 'phase2',
                        offset: 200,
                        header: { annotation: { content: 'Second phase' } },
                        style: { fill: 'violet' },
                    },
                ],
                phaseSize: 40,
            },
            offsetX: 300,
            offsetY: 200,
            height: 200,
            width: 350,
        },
    ];

    @ViewChild("diagram")
    public diagram?: DiagramComponent;

    public updatePhase(): void {
        let swimlane:NodeModel = (this.diagram as Diagram).getObject('swimlane');
        if (swimlane) {
            const phase =  ((swimlane.shape) as ShapeModel | any).phases[0];
            phase.header.style.fill = 'orange';
            phase.header.annotation.content = 'phase updated';
            (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));

Phase interaction capabilities

Resizing phases

  • Phases can be resized using their selection handles.
  • The phase header must be selected first to enable phase selection.
  • When a phase is resized, the associated lane size updates automatically to maintain layout consistency.

Resizing helper functionality

  • A specialized resize selector is used for phase resizing operations.
  • The resize cursor appears in different directions based on swimlane orientation: left and bottom directions for horizontal swimlanes, and top and bottom directions for vertical swimlanes.

Phase header editing

The diagram component provides support for editing phase headers at runtime through double-click interaction. Double-clicking the header label enables inline editing functionality, allowing users to modify phase titles directly within the diagram.

The following image illustrates the phase header editing process:

Phase Header Editing