揭秘 LogicFlow 的拓展机制

前言

自从 LogicFlow 正式开源后,受到的关注比咱们想象的要多。在最开始打算要作 LogicFlow 的时候,咱们花了不少的精力去讨论要作一个什么样的流程可视化库。其中一个选择是基于现有的业务直接实现一个开箱即用,包括了全部的流程编辑库经常使用功能的库。可是最终仍是没有选择这样作,由于咱们当时的背景是:不一样的项目中,在流程图的外观、后台所需数据格式都存在较大的差别。 有些项目用的是 activity, 有些是某些团队自研的流程引擎。因此咱们须要作一个能支持各系统平滑迁移的流程可视化库,须要这个库足够的灵活,视觉上也要知足个各系统本身的风格,并且最好是流程图上的各类功能均可以自按需使用。javascript

基于插件化的拓展机制

配置化 or 插件化?

咱们对于如何将 LogicFlow 实现成一个足够灵活的流程可视化库存在两种想法。一种是一切皆可配置,也就是配置化。这个是不少可视化库的作法,最典型的就是 ECharts,用过 ECharts 的人应该都知道,它的配置功能特别丰富,几乎能够作到配置任何图上的元素的效果,从而达到业务开发者须要的自定义效果。html

可是对于咱们来讲,配置化为了保持其提供足够的灵活性,咱们须要在内部维护太多的 UI 相关的逻辑。以一个节点为例:前端

LogicFlow1

若是是采用配置化的方式的话,开发者传入的配置大体是:java

{
  type: 'rect',
  icon: 'https://example-icon.com/settings.png',
  text: '22\n33333',
}
复制代码

咱们就须要在内部代码中判断传入的参数是否有 icon,若是有,就在左上角显示 icon。可是有的流程但愿本身在左上角显示的是文本,咱们可能就要再增长一个字段 nodeText 来控制了。那若是咱们想显示一个图标在右边呢?想里面显示 3 列文本呢?node

总的来讲,配置化虽然对业务开发者足够友好,只须要文档足够完善,库内部兼容的效果足够多,就能够达到很好的效果。可是对于咱们来讲倒是须要付出很大的成本去实现各类效果,并且极可能由于一些其余状况,舍弃支持一些不经常使用的效果。从长远来看,这种配置化方案对咱们来讲仍是不够灵活的。git

另外一种方案就是插件化,就是将不断变化的非核心功能分散到插件中,避免其与核心代码耦合,保持其核心部分代码简洁和稳定。在插件化方案下,咱们就能够实现一个支持设置 icon 节点就行了,至于其它特殊需求的节点,就有用户本身利用自定义机制来实现便可。并且开放到社区后,其它开发者自定义的内容也能够当作一个插件,贡献到 LogicFlow 中来。github

插件化会带来不少好处:json

  1. 让更多前端社区的人参与进来,即便插件部分写的代码存在问题,也不会影响核心代码。
  2. 二次扩展开发,好比咱们计划以后会在扩展包中实现一个 lf-bpmn 插件,使用此插件能够兼容 bpmn2.0 规范的流程设计器。也能够增长一个绘制 venn 图的 lf-venn 插件,来实如今使用 LogicFlow 绘制 venn 图。甚至之后能够每种形态的流程图编辑,咱们均可以实现一个对应的插件。
  3. 灵活的自定义功能,菜单、工具栏、画板等都作成插件,开发者以为不符合他们业务需求,则能够不用这些插件而是改为本身开发。

API 健全性&稳定性

什么是插件?插件是在核心程序上遵循其提供出来的接口规范再次编写的出来的程序。插件是不能脱离核心程序单独存在的,是一种对核心程序功能的扩展。因此我的以为插件化最重要的一点就是核心程序的 API 健全性和稳定性。若是咱们的 API 不够完善,社区开发者是没法开发出符合其需求的插件;若是咱们的 API 变化很大,颇有可能致使以前开发的插件在咱们版本升级后就不能用了,会致使整个 LogicFlow 的社区生态混乱。微信

为了保证 API 的健全性和稳定性,咱们作了这些事情:markdown

  1. 严格遵循开源版本规范。保障 LogicFlow 的发版对周边生态影响的可控。
  2. API 变化的时候重点考虑向前兼容。
  3. 经过足够多的内置插件来验证 API 的健全性和稳定性。

内置插件

若是咱们只提供表示这图编辑部分的@logicflow/core,那么意味 LogicFlow 就是一个半成品,既不利于推广,也不利于上手使用。因此咱们将 LogicFlow 将非核心功能例如菜单、工具栏等组件; 各种特点形态节点; 一些常见的流程实际应用场景等都采用插件的方式实现放到了@logicflow/extension包中。其中就有 bpmn-js 插件,这里我大体介绍一下 LogicFlow 是如何如何利用插件机制,去实现兼容 bpmn-js 的插件。

  1. 首先是 bpmn-js 中的各类节点和连线,好比用户节点(userTask)、判断节点(gateWay)、顺序流(sequenceFlow)等,咱们利用 LogicFlow 自定义节点和自定义连线机制, 将全部的 bpmn-js 须要的基础图形封装成 BpmnElement 插件。
  2. LogicFlow 默认生成的数据格式是节点和边组成的 json, 而 bpmn-js 须要生成的数据格式是知足 bpmn 2.0 标准的xml。因此咱们提供了一个 BpmnAdapter,在数据输入到 LogicFlow 的时候将 bpmn xml 转换为 LogicFlow Data, 在输出的时候又将 LogicFlow Data 转换为 bpmn xml.
  3. 最后咱们再把流程图绘制过程当中须要用到的菜单、画板、快捷工具等利用 LogicFlow 的自定义组件功能,封装成 Bpmn Component 组件。
  4. 将上面的三个插件,一块儿封装为 Bpmn 插件。

LogicFlow2

LogicFlow 自己只是一个单纯的流程图编辑器,不带有业务属性。为了更好的易用性,咱们提供了 Bpmn-js 插件,让使用 bpmn-js 的项目可以快速替换。有了 Bpmn 插件后,直接经过 LogicFlow 装载 bpmn 插件,这个页面就表现成为 bpmn-js 了。

import LogicFlow from '@logicflow/core';
import { Bpmn } from '@logicflow/extension';

LogicFlow.use(Bpmn);
复制代码

LogicFlow 的拓展能力

前面提到过,插件的扩展性是否强大,是看核心程序提供的 API 是否有足够的扩展性。LogicFlow 在绝大多数 API 上的设计,其目标就是支持的拓展能力。咱们在@logicflow/extension中开发的插件,也是一种验证咱们 API 的方式。从下图能够看到LogicFlow 在支持拓展能力上的总体思路。

LogicFlow3

自定义节点

为了提升易用性,在节点方面,LogicFlow 内置了基础节点,而后在@logicflow/extension中也实现了一些特殊节点。开发者在实际使用中,能够基于这些基础节点和特殊节点进行自定义知足其业务需求的节点。

  1. 基础节点: 在@logicflow/core内部有一个 BaseNode 抽象类,这个类中实现了流程图中节点所需的绝大部分逻辑,例如节点拖动、点击等事件处理和连线处理等。同时也有获取节点外观属性、获取节点基础属性、获取节点配置自定义属性等能够被子类重写的方法。
  2. 内置节点:BaseNode 是抽象类,为了易用性,咱们在 LogicFlow 中还内置了一些基础图形的节点。好比矩形(RectNode)、圆形(CircleNode)、菱形(DiamondNode)和多边形(PolygonNode)。
  3. 扩展节点:为了让开发者在使用的减小接入成本,LogicFlow 除了在核心包中提供了内置节点给与开发继承自定义外,还在扩展包@logicflow/extension中提供了更多的节点。例如圆柱体(CylinderNode)、带有图标的矩形(RectIconNode)等。
  4. 自定义节点:开发者能够在本身的项目中基于 LogicFlow 中的任何一种节点(包括@logicflow/extension中的节点),采用继承重写对应的方法,实现本身业务需求的节点。一样,开发者本身自定义的节点也能够成为插件,开源到社区中。后续咱们会增长 LogicFlow 的插件市场,到时你们能够自由选择本身项目所需的节点。

LogicFlow4

自定义节点规则

在某些时候,咱们可能须要控制连线的链接方式,好比 A 节点不能做为连线的起点、B 节点不能做为连线的终点、C 节点后面必须是 A 节点等等。LogicFlow 提供了自定义节点规则功能来实现这个需求。

LogicFlow 内部有getConnectedSourceRulesgetConnectedTargetRules两个公共方法,分别返回当前节点做为连线开始点和做为链接目标点时的校验规则。当在面板上进行连线操做的时候,会判断全部的规则是否经过,只有经过了才能链接。

class CnodeModel extends RectModel {
  /* ignore other code*/
  // 判断这个节点的下一个节点是否符合自定义要求
  getConnectedSourceRules(): ConnectRule[] {
    const rules = super.getConnectedSourceRules();
    const gateWayOnlyAsTarget = {
      message: 'C节点下一个节点只能是A节点',
      validate: (source: BaseNode, target: BaseNode) => {
        let isValid = true;
        if (target.type !== 'a-node ') {
          isValid = false;
        }
        return isValid;
      },
    };
    rules.push(gateWayOnlyAsTarget);
    return rules;
  }
  // 判断这个节点的上一个节点是否符合自定义要求
  getConnectedTargetRules() {}
}
复制代码

自定义连线

自定义连线方案和自定义节点基本一致,由基础连线实现线的绝大部分逻辑,而后在内置连线中实现连线的特殊交互处理,最后再由开发者基于内置连线进行自定义开发。固然,因为绝大多数图编辑上线的表现形式都只有直线、折线和曲线三种形式,因此通常开发者自定义连线都是改变一下样式(颜色、虚线)和名字(如Bpmn中连线叫作bpmn:sequenceFlow)。

LogicFlow4

自定义属性

通常来讲,对于一个节点,咱们只须要typexytext就能够完整的图中的一个节点的全部可见信息了。type控制这个节点的类型,xy控制着节点所处的位置,text控制着节点上的文本。 可是在实际使用中,咱们可能须要将更多的带有业务性质的属性放到节点上,而后在基于这些业务属性,在节点显示的作出对应处理。例如在流程中,咱们须要将某些节点高亮,表示这些节点正处于异常状态。

LogicFlow 中提供了一个properties字段用于开发者存放本身业务相关的属性,而后能够在自定义节点的时候,基于这些properties本身进行处理。

lf.register('custom-process', ({TriangleNode,TriangleModel }) => {
  class CustomProcessNode extends TriangleNode {
    static extendKey = 'CustomProcessNode';
    getShapeStyle() {
      const attributes = super.getShapeStyle();
      const properties = super.getProperties();
      // 判断自定义属性customStatus是否为error,
      // 若是是,则将这个节点的填充颜色设置为红色。
      if (properties.customStatus === 'error') {
        attributes.fill = 'red'
      }
      return attributes;
    }
  }
  return {
    view: CustomProcessNode,
    model: PolygonNodeModel,
  };
});
复制代码

上面的代码自定义了一个 custom-process 节点,当传入的数据中节点 type 为 custom-process,节点属性中 customStatus 为 error 的时候,流程图上显示的就是一个红色的三角形。

自定义组件

在 LogicFlow 中,除了节点和连线这种由 svg 渲染的图形外,还存在着一些用于图编辑过程当中进行控制的组件,这些组件 LogicFlow 是经过 html 来实现的(好比菜单、控制面板等)。LogicFlow 开放了在图上插入 DOM 的能力,开发者就能够基于这个能力来实现自定义组件。

有了在图上自由插件 DOM 的能力,咱们就能够作不少事情了,好比能够实现一个自由调整节点颜色、字体大小的工具。这个工具的开发就只须要按照咱们正常前端开发便可。而后在监听到用户选中节点后,将这个 DOM 插入到节点对应的位置旁边。

主题

上面咱们提到过能够用自定义节点来定制任何节点的外观,可是对每一个节点都单独自定义一次太多麻烦。LogicFlow 提供了主题功能,来统一设置因此节点的外观基础属性。好比咱们想让全部的矩形都不带边框。

lf.setTheme({
  rect: {
    strokeWidth: 0
  },
})
复制代码

主题除了能够设置节点和连线的外观之外,还能够设置内部功能的样式,好比文本、对齐线等。

最后

经过上面的介绍,你们对 LogicFlow 的拓展机制应该有了必定的了解。LogicFlow 自己不是一个专门处理某个场景的流程设计工具,而是一个流程图编辑库。大多数状况下,拓展性强就意味着没法开箱即用,为了让 LogicFlow 成为一个开箱即用的库,LogicFlow 采用了插件化的机制,经过插件,将场景限定到实际业务场景中来。

LogicFlow 仍是一个很新的开源项目,提供的插件还不够丰富,也存在业务场景考虑不周的状况,欢迎你们在 github 上提 issue,咱们必定会认真对待每个 issue!LogicFlow 也在寻找 contributor ,若是你感兴趣的话,欢迎一块儿来共建!

更多阅读资料:

相关文章
相关标签/搜索