BPMN Text Annotation in Angular Diagram Component

23 Aug 202520 minutes to read

Overview

A BPMN object can be associated with a text annotation that provides additional details about objects within a flow without affecting the actual process flow. Text annotations serve as documentation elements that help explain or clarify specific aspects of the BPMN diagram.

A TextAnnotation points to or references another BPMN shape through the textAnnotationTarget property. When the target shape is moved or deleted, any TextAnnotations attached to the shape will automatically move or be deleted as well. This ensures that TextAnnotations remain associated with their target shapes, though the TextAnnotation can be repositioned to any offset from its target.

The annotation element can be switched from one BPMN node to another by simply dragging the source end of the annotation connector to the desired BPMN node. By default, the TextAnnotation shape includes a connection to its target.

Key properties

The textAnnotationDirection property controls the shape direction of the text annotation. By default, this property is set to Auto, which automatically determines the optimal direction based on the target’s position.

To set the size for text annotation, use the width and height properties of the node.

The offsetX and offsetY properties determine the distance between the BPMN node and the TextAnnotation.

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

@Component({
imports: [
         DiagramModule
    ],

providers: [BpmnDiagramsService],
standalone: true,
    selector: "app-container",
    template: `<ejs-diagram #diagram id="diagram" width="100%" height="700px" >
        <e-nodes>
            <e-node id='event1' [offsetX]=400 [offsetY]=200 [width]="70" [height]="70"  [shape]='shape'></e-node>
            <e-node id='textNode1' [offsetX]=400 [offsetY]=400 [width]="70" [height]="70"  [shape]='shape1'>
                <e-node-annotations>
                    <e-node-annotation content='textNode1'></e-node-annotation>
                    </e-node-annotations>
            </e-node>
            <e-node id='textNode2' [offsetX]=600 [offsetY]=400 [width]="70" [height]="70"  [shape]='shape2'>
                <e-node-annotations>
                    <e-node-annotation content='textNode2'></e-node-annotation>
                    </e-node-annotations>
            </e-node>
        </e-nodes>
    </ejs-diagram>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public shape: BpmnShapeModel = {
        type: 'Bpmn',
        shape: 'Event',
        event: { event: 'Start', trigger: 'None' },
    }
    //Node with target
    public shape1: BpmnShapeModel = {
        type: 'Bpmn',
        shape: 'TextAnnotation',
        textAnnotation:{ textAnnotationDirection:'Auto',textAnnotationTarget:'event1'}
    }
    //Node without target
    public shape2: BpmnShapeModel = {
        type: 'Bpmn',
        shape: 'TextAnnotation',
        textAnnotation:{ textAnnotationDirection:'Auto',textAnnotationTarget:''}
    }
   
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Text Annotation in Palette

Text annotation nodes can be rendered in the symbol palette alongside other BPMN shapes. The following example demonstrates how to render BPMN text annotation nodes in the symbol palette.

import { BpmnDiagrams, BpmnFlowModel, BpmnGatewayModel, Diagram, DiagramModule, SymbolPaletteModule,SymbolPalette, NodeModel, PaletteModel, DiagramComponent  } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation } from '@angular/core';
SymbolPalette.Inject(BpmnDiagrams);
Diagram.Inject(BpmnDiagrams);

@Component({
    imports: [
        DiagramModule, SymbolPaletteModule
    ],

    providers: [],
    standalone: true,
    selector: "app-container",
    template: `<div style="width: 100%">
    <div id="palette-space" class="sb-mobile-palette">
      <ejs-symbolpalette
        id="symbolpalette"
        width="100%"
        height="150px"
        [symbolHeight]="100"
        [symbolWidth]="100"
        [palettes]="palettes"
        [getNodeDefaults]="getSymbolDefaults"
      >
      </ejs-symbolpalette>
    </div>
    <div id="diagram-space" class="sb-mobile-diagram">
      <div class="content-wrapper">
        <ejs-diagram #diagram id="diagram" width="100%" height="700px">
        </ejs-diagram>
      </div>
    </div>
  </div>
  `,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    public palettes?: PaletteModel[];
    public diagram?: DiagramComponent;
    public shape: BpmnFlowModel = {
        type: 'Bpmn',
        flow: 'Association',
        association: 'Directional',
    };
    public getBPMNShapes(): NodeModel[] {
        let bpmnShapes: NodeModel[] = [
            {
                id: 'Start',
                width: 35,
                height: 35,
                shape: {
                    type: 'Bpmn',
                    shape: 'Event',
                    event: { event: 'Start' },
                },
            },
            {
                id: 'Gateway',
                width: 35,
                height: 35,
                offsetX: 100,
                offsetY: 100,
                shape: {
                    type: 'Bpmn',
                    shape: 'Gateway',
                    gateway: { type: 'Exclusive' } as BpmnGatewayModel,
                },
            },
            {
                id: 'DataObject',
                width: 35,
                height: 35,
                offsetX: 500,
                offsetY: 100,
                shape: {
                    type: 'Bpmn',
                    shape: 'DataObject',
                    dataObject: { collection: false, type: 'None' },
                },
            },
            {
                id: 'textAnnotation',
                width: 35,
                height: 35,
                shape: {
                    type: 'Bpmn',
                    shape: 'TextAnnotation',
                },
            },
        ];
        return bpmnShapes;
    };
    public getSymbolDefaults(symbol: NodeModel): void {
        symbol.width = 100;
        symbol.height = 100;
    };
    ngOnInit(): void {
        this.palettes = [{
            id: 'bpmn',
            expanded: true,
            symbols: this.getBPMNShapes(),
            iconCss: 'shapes',
            title: 'BPMN Shapes',
        }]
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Connect the TextAnnotation to BPMN Node

Users can drag and drop any BPMN shapes from the palette to the diagram and establish connections between BPMN nodes and text annotations through interactive manipulation.

The following image demonstrates how to drag a symbol from the palette and connect the text annotation to a BPMN node using interaction.

Text annotation GIF

Text Annotation Direction

The text annotation supports several directional orientations to optimize the visual layout of the diagram:

Text annotation direction Description Image
Auto Automatically determines the optimal direction based on target position BPMN text annotation direction auto
Left Positions the annotation to the left of the target BPMN text annotation direction left
Right Positions the annotation to the right of the target BPMN text annotation direction right
Top Positions the annotation above the target BPMN text annotation direction top
Bottom Positions the annotation below the target BPMN text annotation direction bottom

Add Text Annotation at Runtime

Text annotations can be added dynamically using either the addTextAnnotation method or the add method of the diagram. The following example shows how to use these methods to add a text annotation node programmatically.

import { DiagramModule, BpmnDiagramsService, ShapeStyleModel, randomId,DiagramComponent, NodeModel, BpmnShapeModel  } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';

@Component({
imports: [
         DiagramModule
    ],

providers: [BpmnDiagramsService],
standalone: true,
    selector: "app-container",
    template: `<button (click)="addTextAnnotation()">Add text Annotation</button><button (click)="addTextAnnotationNode()">Add text Annotation Node</button><button (click)="addTextAnnotationAlone()">Add text Annotation Alone</button><ejs-diagram #diagram id="diagram" width="100%" height="700px" [getNodeDefaults] ='getNodeDefaults' >
        <e-nodes>
            <e-node id='event1' [offsetX]=200 [offsetY]=200 [width]="70" [height]="70"  [shape]='shape'></e-node>
        </e-nodes>
    </ejs-diagram>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    @ViewChild("diagram")
    public diagram?: DiagramComponent;
    public shape: BpmnShapeModel = {
        type: 'Bpmn',
        shape: 'Event',
        event: { event: 'Start', trigger: 'None' },
    }
    public getNodeDefaults(node: NodeModel): NodeModel {
        node.height = 100;
        node.width = 100;
        return node;
    }

    public addTextAnnotation(): void {
        let event =  (this.diagram as DiagramComponent).nodes[0];
        let textAnnotation = {
          name: 'newAnnotation' + randomId(),
          angle: 0,
          length: 100,
          width: 100,
          height: 40,
          text: 'New Annotation',
        };
        /**
         * parameter 1 - TextAnnotation to be added
         * parameter 2 - The parent node where the text annotation will be added as a child.
         */
         (this.diagram as DiagramComponent).addTextAnnotation(textAnnotation, event);
    }

    public addTextAnnotationNode(): void {
        let textAnnotation = {
            id: 'textAnnotation' + randomId(),
            offsetX: 300,
            offsetY: 100,
            width: 100,
            height: 40,
            annotations: [{ content: 'Text Annotation' }],
            shape: {
              type: 'Bpmn',
              shape: 'TextAnnotation',
              textAnnotation: {
                //Parent node of text annotation
                textAnnotationTarget: 'event',
                textAnnotationDirection: 'Auto',
              },
            },
          };
          /**
           * parameter 1 - TextAnnotation to be added to the event node
           */
           (this.diagram as DiagramComponent).add(textAnnotation as any);
    }

    public addTextAnnotationAlone(): void {
        let textAnnotation = {
            id: 'textAnnotationAlone' + randomId(),
            offsetX: 300,
            offsetY: 300,
            width: 100,
            height: 70,
            annotations: [{ content: 'Text Annotation' }],
            shape: {
              type: 'Bpmn',
              shape: 'TextAnnotation',
            },
          };
          /**
           * parameter 1 - TextAnnotation to be added to diagram without parent
           */
           (this.diagram as DiagramComponent).add(textAnnotation as any);

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