胖蔡说技术
随便扯扯

聊一聊bpmn-js中的Palette

bpmn-js 阅读指南:

bpmn-js中使用Modeler进行流程图的建模,而Palette则是其内部创建的提供左侧工具栏的插件。插件使用didi实现的依赖注入,其创建使用参考上一篇文章:推荐前端一个轻量级别的依赖注入库:didi

Palette实现主要依托三个功能模块:Eventbus(详情参考bpmn-js 事件总线处理)、diagram-jsPalette插件(之后简称Palette)以及bpmn-js中的PaletteProvider(之后简称PaletteProvider)。左侧工具栏的加载原理是:作为Palette的提供方PalettProvider则需要在插件注册之前通过Palette提供的注册器registerProvider注册监听并通过_rebuild会发送一个palette.getProviders事件,将当前提供者添加到Palette的集合中。Palette加载后通过eventbus监听整体页面绘制事件,当页面绘制后Palette将会回调内置_rebuild方法获取小工具栏组件信息,这时候我们的PaletteProvider也已经完成了注册,Palette会通过_rebuild重绘完成整体小工具栏区域的加载。接下来我们了解下bpmn-js中的左侧小工具栏的加载流程。

PaletteProvider

可以简单的认为它是最终的提供方,小工具栏上面有什么说到底还是由它决定的。在bpmn-js源码中内置了一个”paletteProvider“,也就是说我们可以什么都不做会有一套默认的小工具栏供我们使用。我们想对其进行修改bpmn-js提供给我们两种方式:完全自定义动态增加。我们先暂时忘掉这两种方式,首先来看下如何去实现一个PaletteProvider的角色(插件定义细节请查看:推荐前端一个轻量级别的依赖注入库:didi)。

注册

想要成为一个PaletteProvider的角色,我们就必须要通过diagram-jspalette的插件进行注册。

// Palette提供者
function PaletteProvider(palette,...){
  ....
  palette.registerProvider(this);
}

//必须要有diagram-js的palette插件
PaletteProvider.$inject = ['palette']

提供

注册完成后当Palette需要我们绘制的时候我们就需要提供给Palette到底绘制哪些工具?如何绘制?这时候我们需要提供,这里有个核心的方法就是getPaletteEntries,这个方法是Palette获取小工具集合的必须包含的方法,该方法需要我们返回一个对象,对象里可以有多个工具,对象格式姑且以PaletteEntry标识,且所有注册的提供者的集合会被整合。

// 工具对象格式
type PaletteEntry = {
  action: (event: Event, autoActivate: boolean) => any || {}; // 事件回调,或者是事件对象如{dragStart:()=>{}}
  className?: string; // 类名,这里可用作加载字体图标
  group?: string; // 区域划分
  html?: string; // 自定义html显示
  imageUrl?: string; // 图标链接地址
  separator?: boolean;
  title?: string; // 悬停显示文字
};

// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
   return  {
      'hand-tool': {
        group: 'tools',
        className: 'bpmn-icon-hand-tool',
        title: '手型工具',
        action: {
          click: function(event) {
            handTool.activateHand(event);
          }
        }
      },
    }
}

上述是手型工具的提供方式,我们常规使用的事件处理也就dragstart、click两种,以下是bpmn-js提供的创建action的方式:

  function createAction(type, group, className, title, options) {

    function createListener(event) {
      var shape = elementFactory.createShape(assign({ type: type }, options));

      if (options) {
        var di = getDi(shape);
        di.isExpanded = options.isExpanded;
      }

      create.start(event, shape);
    }

    return {
      group: group,
      className: className,
      title: title,
      action: {
        dragstart: createListener,
        click: createListener
      }
    };
  }

// 上述用到了其他的依赖插件,需要我们在$inject中声明并通过构建函数传入
PaletteProvider.$inject = [
  'palette',
  'create',
  'elementFactory',
  'spaceTool',
  'lassoTool',
  'handTool',
  'globalConnect',
  'translate'
];

如上createListener提供的是工具的绘制方法,这里使用的bpmn-js提供的几种svg图形绘制,当然若有需要我们也可以自己绘制,这个后续文章会深入讨论。

PaletteProvider既然已经了解完成,这里我们来说下开始的时候说的两种小工具的方式:完全自定义动态增加

  • 完全自定义:将插件名命名为:‘paletteProvider’,会自动覆盖已有的paletteProvider插件。
// 将声明设置为paletteProvider
export default {
  __init__: ['paletteProvider'],
  paletteProvider: ['type', PaletteProvider],
}

// 修改PaletteProvider.js 的getPaletteEntries 
// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
   ......
   return  {
      'hand-tool': {
        group: 'tools',
        className: 'bpmn-icon-hand-tool',
        title: '手型工具',
        action: {
          click: function(event) {
            handTool.activateHand(event);
          }
        }
      },
    }
}

这样加载后就如上一样只剩一个小小的手型工具了。

  • 动态增加:若只是想加一个新的工具进去,完全可以自定义一个名字,设置号group分区就可以,我们这里还是以上述为例修改下group,需要注意的是工具名需要修改, 不然可能会无效,试试效果:
// 自定义名称
export default {
  __init__: ['customProvider'],
  customProvider: ['type', PaletteProvider],
}

// 修改PaletteProvider.js 的getPaletteEntries 
// 改方法必须有
PaletteProvider.prototype.getPaletteEntries = function() {
   ......
   return  {
      'hand-tool-2': {
        group: 'activity',
        className: 'bpmn-icon-hand-tool',
        title: '手型工具2',
        action: {
          click: function(event) {
            handTool.activateHand(event);
          }
        }
      },
    }
}

这样在activity区域就多了一个手型工具了

Palette

diagram-jsPalette插件可以说是整个bpmn-js的左侧工具的管理模块了,它定义了PaletteProvider的注册方式、提供方法已经工具的类型格式。这里我们来看下几个核心的功能部分。

提供注册

Palette内部实现了一个registerProvider方法来让PaletteProvider进行注册登记,并通知Palette构建组件信息,通过eventbus方式将其加载到内部的event


// 注册实现
Palette.prototype.registerProvider = function(priority, provider) {

   ...
  // 添加监听将provider加载到内部的event中
  this._eventBus.on('palette.getProviders', priority, function(event) {
    event.providers.push(provider);
  });

  this._rebuild();
};

// 组件构建部分
Palette.prototype._rebuild = function() {
  // 这里用于发送信息让注册方法的监听添加provider
  var providers = this._getProviders();
 ...
  this._update();
};

// 这里是发送获取组件的消息
Palette.prototype._getProviders = function(id) {
  var event = this._eventBus.createEvent({
    type: 'palette.getProviders',
    providers: []
  });
  this._eventBus.fire(event);
  return event.providers;
};

监听绘制

Palette插件开始加载的时候会监听diagram-js的绘制事件,并在合适的时机重写加载绘制组件:

export default function Palette(eventBus, canvas) {



......
 // toolMananger插件用于协助管理palette组件的编辑状态
  eventBus.on('tool-manager.update', function(event) {
    var tool = event.tool;
    self.updateToolHighlight(tool);
  });

  // 国际化监听
  eventBus.on('i18n.changed', function() {
    self._update();
  });

  // diagram初始化监听
  eventBus.on('diagram.init', function() {
    self._diagramInitialized = true;
    self._rebuild();
  });
}

如上就是本篇文章的所有的内容了,若是感兴趣或是觉得对你有所帮助,欢迎关注一直在前端路上陪伴你的胖蔡~

赞(1) 打赏
转载请附上原文出处链接:胖蔡说技术 » 聊一聊bpmn-js中的Palette
分享到: 更多 (0)

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏