DEV Community

Nour Assy for Process Analytics

Posted on

Getting Started with bpmn-visualization

Online monitoring data visualized on a BPMN process

Welcome to the Process Analytics series of tutorials 👋

The Process Analytics project consists of open source libraries and components that allow you to get a visual overview of your business process and the process execution data.

In this introductory tutorial, you will learn how to use bpmn-visualization, a TypeScript library for visualizing process data on top of process models expressed in BPMN which is the de facto standard for process modeling.

⚠️ This tutorial assumes that you have a basic understanding of HTML, CSS and JavaScript. We provide a ready to use bootstrap template so that you can directly start the development 🚀 without getting your hands dirty with the project configuration 🤕. There will be a lot of examples, so go ahead, and initialize your project 👇

Initialize your project

To follow and reproduce the tutorial steps in your own environment, we created a preconfigured project template that you can open with your preferred local or online IDE (e.g. gitpod, CodeSandobx, etc.). Follow the steps below to set up and initialize the project template.

Step 1: git clone the repository or download the zip and open it in your favorite IDE.

Step 2: Open a terminal window in the project location and run the commands below.

If you’re using an online editor like gitpod, these two commands may be automatically launched, and you should directly see the message shown in the figure below.

If you’re using a local editor, you must install Node.js and the npm command line interface. You can check the details here. This tutorial has been tested with Node 16 and npm 8.16.0.

npm install
npm start
Enter fullscreen mode Exit fullscreen mode

npm install installs the required packages while npm start starts a dev server that will continuously update the page while you are updating the code. We use Vite JS which is a front-end development platform for modern web projects.

If the commands are successfully executed, you should see the message below which states that Vite JS has launched a dev server available at http://localhost:5173/. Click on the link to see the code output. The page will be automatically updated whenever you make changes to the code.

VITE JS output

Let’s take a quick look at the main project structure. The src package contains two files: index.js in which we will add the JavaScript code related to the usage of bpmn-visualization and styles.css in which we will add CSS classes to apply custom styles. The index.html contains the HTML code that will be kept unchanged in this tutorial.

Project structure

Before diving into the technical details, we will briefly explain what the bpmn-visualization library can do for you, then we will show you how to use it in an online monitoring scenario. Let’s go 🎬

What can bpmn-visualization do for you?

bpmn-visualization is a TypeScript library for visualizing process execution data on BPMN diagrams. The version 0.27.0 provides the following features:

  • BPMN graph rendering and fitting options;
  • Display options for execution data which include:
    • adding overlays 📛 to the process model elements (e.g. for displaying statistics computed from process execution data)
    • customizing the style 🖋️ of the process model elements including colors, fonts, sizes and icons (e.g. for highlighting performance issues, errors and warning)
  • Interactive capacities with the process model elements (e.g. adding tooltips on mouse hover/click)

The general architecture revolves around three key components: BPMN parser, BPMN renderer and interactions.

General architecture of bpmn-visualization

The BPMN parser loads XML BPMN files, and converts them into an internal model. The internal BPMN model is then passed to the BPMN renderer component, which is in charge of rendering the BPMN elements. The interactions component empowers developers and end users with flexibility in interacting with the BPMN elements. For more information, check out the bpmn-visualization user documentation.

Use case of this tutorial: an online monitoring scenario ⏲️

You will learn how to use bpmn-visualization by taking a concrete process analytics scenario which is_ online monitoring_. In online monitoring, an administrator monitors the execution of the process at run-time. Using bpmn-visualization, we will load a BPMN process and display two important pieces of information:

  1. The running instances and their number ⚙️.
  2. The state of running instances: whether or not they are violating the pre-defined KPIs ⏱️.

Let’s see now how it works in practice 👩‍💻

How to use bpmn-visualization?

If you are stuck at any step in the tutorial, you can find the complete solution here.

The user of bpmn-visualization is responsible for retrieving the BPMN diagram which could be a local or a remote file fetched via an API. We will use a BPMN diagram available from bpmn-miwg-test-suite which provides a collection of BPMN test cases created by the OMG BPMN Model Interchange Working Group (BPMN MIWG) to test the interoperability between different BPMN tools.

Create a diagram.bpmn file in your src directory and copy the content of the C.1.0 BPMN file.

Initialize bpmn-visualization and load the diagram

For the remainder of this part, make sure to check the bpmn-visualization API documentation.

The first step consists of importing and instantiating the BpmnVisualization class. For the instantiation, we will pass as input the id of the HTML element where the BPMN diagram will be rendered (in our case, bpmn-container is the id of the HTML element declared in index.html). Additionally, we can set the navigation to true to enable the diagram panning and zooming.

Edit the src/index.js file by removing the placeholder code and adding the following:

import { BpmnVisualization } from 'bpmn-visualization';

const bpmnVisualization = new BpmnVisualization({
 container: 'bpmn-container',
 navigation: { enabled: true }
Enter fullscreen mode Exit fullscreen mode

Now that a bpmnVisualization object is created and initialized, we can load the diagram by calling the load method. The load method takes as input the BPMN file content as a string, which is in our case the content of the diagram.bpmn file we created previously. Additional parameters can be passed to specify the fitting options (using the enumeration FitType imported from bpmn-visualization) and whether the model needs to be filtered.

Let’s see how to center a diagram on load. First, update the import line of the code above by adding the FitType class. Then, import the content of the diagram.bpmn file as a string and store it in the variable diagram as shown below.

import { BpmnVisualization, FitType } from 'bpmn-visualization';
// the '?raw' parameter tells Vite to store the diagram content in a string.
// for more details, see
// for other load methods, see
import diagram from './diagram.bpmn?raw';
Enter fullscreen mode Exit fullscreen mode

To load the diagram, add the code snippet below right after the initialization of the BpmnVisualization class. The diagram variable is passed to the load method along with the additional parameter fit for which the type property is set to FitType.Center.

bpmnVisualization.load(diagram, {
 fit: { type: FitType.Center }
Enter fullscreen mode Exit fullscreen mode

Save the code and you’ll see the BPMN diagram of our process visualized as shown in the figure below. It consists of two pools, Team Assistant and Process Engine - Invoice Receipt.

BPMN process of an invoice processing

Let’s simplify the model by focusing only on the Process Engine - Invoice Receipt pool. We will modify the load method by adding the modelFilter option. The modelFilter option has the pools property that allows to specify the pools to keep in the model. A pool can be referenced by its id and/or its name. In the code below, we indicate that the pool named Process Engine - Invoice Receipt is kept while the remaining pools are filtered out.

bpmnVisualization.load(diagram, {
 fit: { type: FitType.Center },
 modelFilter: {
   pools: [
       name: 'Process Engine - Invoice Receipt'
Enter fullscreen mode Exit fullscreen mode

The result should be the filtered model below containing only the Process Engine - Invoice Receipt pool. Now that we have the process visualized 🥳, let’s breathe life into it 🌈

BPMN process with a filtered pool

Visualize monitoring data

Add testing data

Let’s first add some testing data. For the purpose of this tutorial, we will mock real data with methods returning arbitrary data. We will define two functions: getActivitiesRunningInstances() for returning information about running activities and getEdgesWaitingInstances() for returning information about process instances waiting on specific edges.

The getActivitiesRunningInstances() returns a Map consisting of key-value pairs where the key is the id of the BPMN activities (as defined in the BPMN file) and the value is an object consisting of the number of on-time, risky and critically running instances.

Add the following code at the end of your src/index.js file.

function getActivitiesRunningInstances() {
  return new Map([
    ['assignApprover', { onTime: 5, risky: 0, critical: 0 }],
    ['approveInvoice', { onTime: 2, risky: 3, critical: 0 }],
    ['reviewInvoice', { onTime: 4, risky: 1, critical: 2 }],
    ['prepareBankTransfer', { onTime: 0, risky: 0, critical: 0 }],
    ['archiveInvoice', { onTime: 0, risky: 0, critical: 0 }],
Enter fullscreen mode Exit fullscreen mode

Similarly, add the getEdgesWaitingInstances() function below which returns a Map consisting of key-value pairs where the key is the id of the edges on which there are waiting instances.

function getEdgesWaitingInstances() {
  return new Map([['invoiceApproved', 2]]);
Enter fullscreen mode Exit fullscreen mode

Interact with BPMN elements of the process diagram

The interaction with the process diagram is done via BpmnElementsRegistry which provides different methods to find and retrieve the BPMN elements of the diagram. In this tutorial, we will cover the addOverlays and addCssClasses.

Add overlays to show the number of running instances ⚙️

The addOverlays method takes as input the id of the BPMN element and one or multiple Overlay objects. An Overlay object is defined in terms of its label, position and style.

The code below illustrates the usage of the method (don’t add it to your code). It adds an overlay to the activity Assign Approver whose id is assignApprover (you can find the id of an element in the src/diagram.bpmn file). The overlay is labeled with “5”. It is positioned in the top-center of the activity. Its style is defined in terms of the font, fill color and stroke.

bpmnVisualization.bpmnElementsRegistry.addOverlays('assignApprover', {
      position: 'top-center',
      label: '5',
      style: {
        font: { color: 'white', size: 16 },
        fill: { color: 'green', opacity: 50 },
        stroke: { color: 'green', width: 2 }
Enter fullscreen mode Exit fullscreen mode

Let’s now add overlays to activities using our testing data. Add the code below to your src/index.js file. The code retrieves and stores the activities’ running instances in the variable activitiesRunningInstances. Then, it iterates over the elements in activitiesRunningInstances using the foreach method. For each element, it adds three overlays: in the top-center for instances running on time, in the top-left for instances running late with a risky level and in the top-right for instances running late with a critical level.

const activitiesRunningInstances = getActivitiesRunningInstances();
activitiesRunningInstances.forEach((value, activityId) => {
  // running on time
  if (value.onTime) {
    bpmnVisualization.bpmnElementsRegistry.addOverlays(activityId, {
      position: 'top-center',
      label: `${value.onTime}`,
      style: {
        font: { color: 'white', size: 16 },
        fill: { color: 'green', opacity: 50 },
        stroke: { color: 'green', width: 2 },
  // running late with risky level
  if (value.risky) {
    bpmnVisualization.bpmnElementsRegistry.addOverlays(activityId, {
      position: 'top-left',
      label: `${value.risky}`,
      style: {
        font: { color: 'white', size: 16 },
        fill: { color: '#FF8C00', opacity: 50 },
        stroke: { color: '#FF8C00', width: 2 },
  // running late with critical level
  if (value.critical) {
    bpmnVisualization.bpmnElementsRegistry.addOverlays(activityId, {
      position: 'top-right',
      label: `${value.critical}`,
      style: {
        font: { color: 'white', size: 16 },
        fill: { color: 'red', opacity: 50 },
        stroke: { color: 'red', width: 2 },
Enter fullscreen mode Exit fullscreen mode

In the same way, information about instances waiting on specific edges can be retrieved by calling the function getEdgesWaitingInstances and storing the result in the map edgesWaitingInstances. Then, overlays can be added to each edge by iterating over the elements in edgesWaitingInstances as shown below:

const edgesWaitingInstances = getEdgesWaitingInstances();
edgesWaitingInstances.forEach((value, edgeId) => {
    bpmnVisualization.bpmnElementsRegistry.addOverlays(edgeId, {
        position: 'middle',
        label: `${value}`,
        style: {
          font: { color: 'white', size: 16 },
          fill: { color: 'red', opacity: 50 },
          stroke: { color: 'red', width: 2 },
Enter fullscreen mode Exit fullscreen mode

The figure below shows the resulting visualization.

BPMN process with overlays

Let’s now customize the style of elements 🎆 to highlight their state with respect to KPIs.

Add CSS classes to highlight the state of running instances ⏱️

Do you remember your first university course Introduction to Web Development? 🕸️ Well, it might be old 👴 (but gold 🙂). Before explaining how addCssClasses works, let’s try to remember the syntax of a CSS class selector. We will define a new CSS class to fill all the process elements with a gray color. To correctly define CSS class selectors, a minimal knowledge of the HTML DOM tree is required. Let’s see what the HTML DOM tree looks like.

Check HTML DOM Structure

In your browser, perform a right click on any BPMN element, for example on the activity Assign Approver. Click on Inspect and check its DOM structure. As shown below, you can see that, in general, a BPMN activity with a specific type (e.g. a user activity as in our case) is defined as an SVG group consisting of two elements: a rectangle rect representing the shape of the activity and a path for drawing the activity icon (the user icon in our case).

HTML DOM inspection

Therefore, when defining a CSS class selector, one should explicitly define the element to which the CSS is applied.

Define CSS class selectors

Since we want to style all our BPMN elements (activities, gateways and events) by filling them with a gray color, it is recommended to reuse the default CSS classes instead of adding new ones. The classes allow identifying elements of the same family and of the same specific type. During BPMN diagram rendering, bpmn-visualization sets these CSS classes to all elements according to their types.

For example, in the above HTML DOM figure, we can see that the activity Assign Approver has the following classes: bpmn-type-activity, bpmn-type-task and bpmn-user-task. The first class indicates that the element is an activity, the second and third classes give more information about the type of the activity: it is a task and more specifically a user task (check the BPMN specification for more details about the different BPMN elements). Therefore, to apply a specific style to all activities (regardless of their type), we can reuse the default CSS class bpmn-type-activity.

Add the CSS code below to your src/styles.css file. This CSS class selector fills all events (more specifically their ellipse element), activities (more specifically their rect element) and gateways (more specifically their first path element) with a gray color.

.bpmn-type-event > ellipse,
.bpmn-type-activity > rect,
.bpmn-type-gateway > path:nth-child(1) {
 fill: rgb(230, 225, 225);
Enter fullscreen mode Exit fullscreen mode

Your process model should now look like the figure below 👇.

BPMN process with overlays and CSS

Use the addCssClasses method

The addCssClasses takes as input the id of one or several BPMN elements and one or more CSS class names to be applied. In this tutorial example, we will write CSS class selectors with some animations to:

  • Highlight the state of running activities’ instances by:
    • Adding a shadow color to activities:
      • 🟢 Green: if all instances are running on time.
      • 🔴 Red: if there exists at least one instance running critically late.
      • 🟠 Orange : if there exists an instance running late with a risky level.
    • Animating the stroke of activities with three different levels of speed following the same strategy as for the shadow colors.
  • Highlight process instances waiting for a specific activity to be executed by:
    • Coloring the input edge of the corresponding activity in 🔴 red.
    • Animating the edge by adding a pulsating effect.

Add the CSS code below to your src/styles.css. The code shows the CSS class selector that will be added to the activities running on time. You don’t really have to be a CSS expert to define cool styles with animations. There are plenty of websites that generate ready to use CSS code for you. Just ask your super search engine 🦹‍♀️ for CSS generators. In our example, the filter property allows defining a shadow. The stroke-dasharray defines the pattern of dashes and gaps on the stroke. The remaining properties are defined for animating the stroke. Particularly, the animation-duration allows us to set the speed of the animation.

.task-running-on-time > rect {
  stroke-dasharray: 10, 5;
  animation-name: dash-task;
  animation-duration: 0.5s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  filter: drop-shadow(0 0 0.95em rgb(6, 146, 3));
@keyframes dash-task {
  to {
    stroke-dashoffset: -15;
Enter fullscreen mode Exit fullscreen mode

The remaining CSS class selectors for tasks running risky (.task-running-risky) and late (.task-running-critical) should be straightforward:

  • Change the color of the shadow in the filter property (set it orange 🟠 for .task-running-risky and red 🔴 for .task-running-critical) , and
  • Increase the animation-duration. For example, you can set it to 1s in .task-running-risky and to 2s in .task-running-critical.

Super easy, right? 🎃

Finally, edit your src/index.js by adding the CSS classes to the activities using the method addCssClasses as shown in the code below:

activitiesRunningInstances.forEach((value, activityId) => {
  if (value.critical) {
  bpmnVisualization.bpmnElementsRegistry.addCssClasses(activityId, 'task-running-critical');
  } else if (value.risky) {
  bpmnVisualization.bpmnElementsRegistry.addCssClasses(activityId, 'task-running-risky');
  } else if (value.onTime) {
  bpmnVisualization.bpmnElementsRegistry.addCssClasses(activityId, 'task-running-on-time');
Enter fullscreen mode Exit fullscreen mode

If you see the first signs of life in your process, then Congratulations 🎊 The result should be similar to the figure below.

BPMN process enriched with online monitoring data

Now could you guess what are the CSS class selectors for animating the edge and getting the final result as shown above in the cover photo of this tutorial? 🧐 Don’t forget to check the HTML DOM structure of edges!


In this tutorial, we learned how to use the bpmn-visualization library using an online monitoring example. We saw that the user of bpmn-visualization is responsible for retrieving the process diagram. Using the library, we loaded a BPMN diagram. Then, we filtered and enriched the process with overlays and CSS classes. The bpmn-visualization API offers a wide range of functionalities that can be explored here.

Going further

In a process analytics scenario, a process model may not be available. It is rather discovered from the execution data recorded by a process-aware information system using process discovery techniques. In a separate tutorial, we will talk about automatically generating BPMN diagrams from process execution data using the Model Generation Application provided also by the Process Analytics project.

That’s all for now! We’ll be glad to receive your feedback and answer your questions, just leave your comment below 👇

Stay tuned for more upcoming tutorials 📚

In the meantime, if you want to stay on top of the latest news and releases from the Process Analytics project, follow us through:

Acknowledgements: we warmly thank Adrien Kantcheff and Emmanuel Duchastenier for having tried the tutorial and reviewed the article.

Hans-Peter Gauster

Photo by Hans-Peter Gauster on Unsplash

Top comments (4)

laurentleseigneur profile image
Laurent Leseigneur

great content!

small tip: you can convert the repo to a Github template

tbouffard profile image
Thomas Bouffard

Yes, thanks for the tip. I have just activated the "template" support 👍

christbryan profile image
christbryan • Edited

Hey thanks for the presentation. I would like to know how can I extract my event logs? In order to get in touch with process mining please.

assynour profile image
Nour Assy

Generating the event logs is out of scope of the Process Analytics project, especially when it first involves extracting data from a specific vendor (Bonita in your case). You will find more information and answers in the Bonita Community Q&A. See also Bonitasoft-Community/bonita-server-logs#2 (comment)