BPMN text annotation in Angular Diagram control

10 Dec 202420 minutes to read

Text annotation

  • A BPMN object can be associated with a text annotation which does not affect the flow but gives details about objects within a flow.

  • A TextAnnotation points to or references another BPMN shape, which we call the textAnnotationTarget of the textAnnotation. When a target shape is moved or deleted, any TextAnnotations attached to the shape will be moved or deleted too. Thus, the TextAnnotations remain with their target shapes though you can reposition the TextAnnotation to any offset from its target. The textAnnotationTarget property of the BpmnTextAnnotation is used to connect an annotation element to the BPMN Node.

  • The annotation element can be switched from a BPMN node to another BPMN node simply by dragging the source end of the annotation connector into the other BPMN node.

  • By default, the TextAnnotation shape has a connection.

  • The textAnnotationDirection property is used to set the shape direction of the text annotation.

  • By default, the textAnnotationDirection is set to a Auto.

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

  • The offsetX and offsetY properties are used to set 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 node can be rendered in symbol palette like other bpmn shapes. The following example shows how to render Bpmn text annotation node in 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

Drag and drop any bpmn shapes from the palette to diagram and connect the BPMN Node and textAnnotation.

The following image shows how to drag a symbol from the palette and connect the textAnnotation to the BPMNNode with interaction.

Text annotation GIF

Text annotation direction

There are several types of Text annotation directions as follows:

Text annotation direction Image
Auto BPMN text annotation direction auto
Left BPMN text annotation direction left
Right BPMN text annotation direction right
Top BPMN text annotation direction top
Bottom 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.

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));