Using bpmn custom platter in vue project

Content overview

This series of "using bpmn XXXX in vue project" is divided into seven parts, all of which are examples used in the process of their own use, original by hand, and are being updated in succession at present. It mainly includes the use examples, application skills, summary of basic knowledge points and matters needing attention of bpmn in vue project, which has certain reference value and can be referred to by friends in need. If you reprint or climb directly through a reptile, the format is particularly ugly, please come to the original: I am the author

previously on

After the learning of the first four chapters, we can realize the basic drawing, preview and color of bpmn. In this chapter, how to customize the left toolbar (platter), first look at the comparison of the effect pictures before and after customization:

Our goal this time is to create a new custom node based on the original element type of platter on the left. Let's call it "strawberry cake" node. The type is bpmn:Task. We can find a nice little strawberry cake pattern by ourselves. So, let's start. First, create a new "customPalette" folder, which contains all our customized files today.

Step 1: create a platter class function named CustomPalette.js

export default class CustomPalette {
  constructor(create, elementFactory, palette) {
    this.create = create;
    this.elementFactory = elementFactory;
  // This is drawing palette Do not change the function name
  getPaletteEntries() {
    const elementFactory = this.elementFactory;
    const create = this.create;
    function dragEventFactory(type) {
      return function (event) {
        const taskShape = elementFactory.create('shape', {
          type: type
        create.start(event, taskShape);
    return {
      'create.cake': {
        title: 'I am a custom node-Strawberry Cake',    // Hover the mouse over the text displayed on the node
        className: 'icon-custom bpmn-icon-cake',   // Style name
        action: {      // Events triggered when the node is operated. At this time, only one drag event can be registered. Otherwise, drag has no effect
          dragstart: dragEventFactory('bpmn:Task')
CustomPalette.$inject = [

At this time, we have registered a node named "create.cake". When dragging it, a node of type "bpmn:Task" will appear in the canvas. At this time, we need to export the file and introduce it into the page, otherwise it will have no effect.

Step 2: at the same level of CustomPalette.js, create an index.js file to export

import CustomPalette from './CustomPalette';
export default {
  __init__: ['customPalette']
  customPalette: ['type', CustomPalette],

Step 3: import index.js into the page (index.vue)

import customModule from './customPalette';
export default {
  mounted() {
    this.containerEl = document.getElementById('container');
    this.bpmnModeler = new BpmnModeler({
       additionalModules: [ customModule ]

Step 4: define the style for the node

Create a new customPalette.scss file, place a picture of "cake.png" at the same level of the file, and write it as the background of the node. If the background image is introduced, it seems that it only supports. png format, pro testing: jpg error reporting

.bpmn-icon-cake {
  background-image: url('./cake.png');
.icon-custom {
  background-size: 65%;
  background-repeat: no-repeat;
  background-position: center center;

And it is introduced in main.js. Note that it must be introduced globally in main.js, otherwise it will not take effect.

import 'customPalette/customPalette.scss';

At this time, we can see the custom strawberry cake node in the left toolbar, but when you drag the node, only one bpmn:Task node will be generated on the right, with only one frame.

What we hope is that the custom icon will also be displayed in the canvas after dragging, so we go to the next step: custom rendering

Step 5: Canvas render custom node

At this time, we need to create a new CustomRenderer.js file, which is used to customize the renderer. Because we are modifying the original bpmn element "bpmn:Task", we need to inherit the BaseRenderer.

import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'; // Bring in default renderer
const HIGH_PRIORITY = 1500; // Highest priority
export default class CustomRenderer extends BaseRenderer {
  // inherit BaseRenderer
  constructor(eventBus, bpmnRenderer) {
    super(eventBus, HIGH_PRIORITY);
    this.bpmnRenderer = bpmnRenderer;
  canRender(element) {
    return !element.labelTarget;
  drawShape(parentNode, element) {
    const shape = this.bpmnRenderer.drawShape(parentNode, element);
    return shape;
  getShapePath(shape) {
    return this.bpmnRenderer.getShapePath(shape);
CustomRenderer.$inject = ['eventBus', 'bpmnRenderer'];

At this time, the structure of CustomRenderer.js file is completed. Note: the high priority variable and canRender cannot be deleted, otherwise there will be problems. The play is the drawShape function inside.

Step 6: write the drawShape function

We create a util file at the same level of CustomRenderer.js to record some properties of the custom type node.

import cake from './cake.png';

// Define the type of element. At this time, we only need to customize one node, so there is only one element in the array
const customElements = ['bpmn:Task']; 
const customConfig = {
  // Configuration of custom elements
  cake: {
    url: cake,
    attr: {x: 0, y: 0, width: 50, height: 50}
export {customElements, customConfig};

Now let's write the drawShape function

import { customElements, customConfig } from './util';
import { append as svgAppend, create as svgCreate } from 'tiny-svg';
drawShape(parentNode, element) {
  const type = element.type; // Get to type
  // All nodes will use this function, so at this time, only those that need to be customized can be customized, otherwise they will still be displayed bpmn Default icon
  if (customElements.includes(type)) {  
    const {url, attr} = customConfig['cake'];
    const customIcon = svgCreate('image', {...attr, href: url});
    element['width'] = attr.width;
    element['height'] = attr.height;
    svgAppend(parentNode, customIcon);
    return customIcon;
  const shape = this.bpmnRenderer.drawShape(parentNode, element);
  return shape;

Step 7: export and use CustomRenderer

Export the index.js file of CustomPalette before modification

import CustomPalette from './CustomPalette';
import CustomRenderer from './CustomRenderer';
export default {
  __init__: ['customPalette', 'customRenderer'],
  customPalette: ['type', CustomPalette],
  customRenderer: ['type', CustomRenderer]

Note: at this time, the property name in 6516; init ᥴ cannot be changed. Do not ask why, because the error is reported when it is changed.

In step 3, the index.js has been introduced into the page. At this time, there is no need to introduce it again. Let's see the effect.

Follow up

Project directory: index.vue is the main page of canvas. There are 6 files under the same level of customPalette folder. The structure is as follows:


The code snippet of each file has been shown in the article, and the folder does not know how to upload to the blog. If you want to get the complete source code or have problems, the official account will contact me, sweep the following two-dimensional code or official account to search for "Lemoncool", and then you can get it.

Lovely you may need more

Tags: Javascript Vue

Posted on Mon, 11 May 2020 05:45:20 -0400 by ToeBee