Getting Started with bpmn-visualization
Tags: javascript, visualization, process, analytics
Published: 2022-10-14 09:38:16


![Online monitoring data visualized on a BPMN process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hip8ppuji1az7v6symep.gif)

Welcome to the [Process Analytics](https://process-analytics.dev/?utm_source=dev.to&utm_medium=display&utm_campaign=tutorial) 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](https://github.com/process-analytics/bpmn-visualization-js/)_, a TypeScript library for visualizing process data on top of process models expressed in [BPMN](https://www.omg.org/spec/BPMN/2.0.2/) 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 👇**

---

<h2>Initialize your project</h2>


To follow and reproduce the tutorial steps in your own environment, we created a [preconfigured project template](https://github.com/process-analytics/bpmn-visualization-tutorial-getting-started) that you can open with your preferred local or online IDE (e.g. [gitpod](https://gitpod.io/), [CodeSandobx](https://codesandbox.io/), etc.). Follow the steps below to set up and initialize the project template. 

**Step 1**: git clone the [repository](https://github.com/process-analytics/bpmn-visualization-tutorial-getting-started) 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](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). This tutorial has been tested with Node 16 and npm 8.16.0.

```
npm install
npm start
```
`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](https://vitejs.dev/) 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/](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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t27upqwal20dmxc32qht.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwzq5bvpjzl0qois0eml.png)

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 🎬 

---

<h2>What can bpmn-visualization do for you?</h2>


_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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffg58z1ak7m22lyc435a.png)

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](https://process-analytics.github.io/bpmn-visualization-js/).

---

<h2>Use case of this tutorial: an online monitoring scenario ⏲️</h2>

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 👩‍💻**

---

<h2>How to use bpmn-visualization?</h2>

> If you are stuck at any step in the tutorial, you can find the complete solution [here](https://github.com/process-analytics/bpmn-visualization-tutorial-getting-started/tree/solution).

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](https://github.com/bpmn-miwg/bpmn-miwg-test-suite) which provides a collection of BPMN test cases created by the [OMG BPMN Model Interchange Working Group (BPMN MIWG)](https://www.omgwiki.org/bpmn-miwg/doku.php) 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](https://github.com/bpmn-miwg/bpmn-miwg-test-suite/blob/9f361228ec34451e6a551846a59f5e4057a35795/Reference/C.1.0.bpmn).

<h3>Initialize bpmn-visualization and load the diagram</h3>

> For the remainder of this part, make sure to check the _bpmn-visualization_ [API documentation](https://process-analytics.github.io/bpmn-visualization-js/api/).

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:

```javascript
import { BpmnVisualization } from 'bpmn-visualization';

const bpmnVisualization = new BpmnVisualization({
 container: 'bpmn-container',
 navigation: { enabled: true }
});
```

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.

```javascript
import { BpmnVisualization, FitType } from 'bpmn-visualization';
// the '?raw' parameter tells Vite to store the diagram content in a string.
// for more details, see https://vitejs.dev/guide/assets.html#importing-asset-as-string
// for other load methods, see https://github.com/process-analytics/bpmn-visualization-examples
import diagram from './diagram.bpmn?raw';
```

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`. 

```javascript
bpmnVisualization.load(diagram, {
 fit: { type: FitType.Center }
}); 
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xcwcojo66a2yovyvvbc3.png)

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. 

```javascript
bpmnVisualization.load(diagram, {
 fit: { type: FitType.Center },
 modelFilter: {
   pools: [
     {
       name: 'Process Engine - Invoice Receipt'
     }
   ]
 }
});
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c1plymqk6jgn5in5e5cf.png)

<h3>Visualize monitoring data</h3>

<h4>Add testing data</h4>

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.

```javascript
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 }],
  ]);
}
```
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. 

```javascript
function getEdgesWaitingInstances() {
  return new Map([['invoiceApproved', 2]]);
}
```

<h4>Interact with BPMN elements of the process diagram</h4>

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`.

<h4>Add overlays to show the number of running instances ⚙️</h4>

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`.

```javascript
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 }
      }
    });
```

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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/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.

```javascript
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 },
      },
    });
  }
});
```
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:

```javascript
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 },
        },
    });
});
```

The figure below shows the resulting visualization. 

![BPMN process with overlays](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u1h4t4hytsrx9q1uz1qq.png)

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

<h4>Add CSS classes to highlight the state of running instances ⏱️</h4>

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](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors). 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.

<h5>Check HTML DOM Structure</h5>

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](https://developer.mozilla.org/en-US/docs/Web/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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztmspzoutnf6ffzt5rmc.png)

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

<h5>Define CSS class selectors</h5>

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](https://www.omg.org/spec/BPMN/2.0/PDF) 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.

```css
.bpmn-type-event > ellipse,
.bpmn-type-activity > rect,
.bpmn-type-gateway > path:nth-child(1) {
 fill: rgb(230, 225, 225);
}
```
Your process model should now look like the figure below 👇.

![BPMN process with overlays and CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmjceynzva97cds21pax.png)

<h5>Use the addCssClasses method</h5>

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.

```css
.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;
  }
}
```
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:

```javascript
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');
  }
});
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ue73ex5ak1q81qj1x2fx.gif)

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!

<h2>Summary</h2>

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](https://process-analytics.github.io/bpmn-visualization-js/api/index.html).

<h3>Going further</h3>

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](http://www.processmining.org/process-discovery.html).  In a separate tutorial, we will talk about automatically generating BPMN diagrams from process execution data using the [Model Generation Application](https://process-analytics.dev/model-generation-application/?utm_source=dev.to&utm_medium=display&utm_campaign=tutorial) 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:

* Website: [https://process-analytics.dev](https://process-analytics.dev/?utm_source=dev.to&utm_medium=display&utm_campaign=tutorial)
* Twitter: [@ProcessAnalyti1](https://twitter.com/ProcessAnalyti1)
* GitHub: [https://github.com/process-analytics](https://github.com/process-analytics)
* Discord: [Join our server!](https://discord.com/invite/HafnBYsRXd)

**_Acknowledgements_**: we warmly thank [Adrien Kantcheff](https://github.com/akantcheff) and [Emmanuel Duchastenier](https://github.com/educhastenier) for having tried the tutorial and reviewed the article.

![Hans-Peter Gauster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6b0yaacvj7f7kh8fqgb.png)

_Photo by [Hans-Peter Gauster](https://unsplash.com/photos/3y1zF4hIPCg)  on [Unsplash](https://unsplash.com?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)_