滴滴开源 LogicFlow:专一流程可视化的前端框架

前言

LogicFlow 脱胎于滴滴技术团队在客服业务下的实践,是由智能中台—体验平台研发的一款流程可视化的前端框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展能力,方便咱们快速在业务系统内知足类流程图编辑器的需求。目前,LogicFlow 已经在公司内外不一样用户的流程配置需求中获得了验证。前端

背景

首先,智能中台—体验平台技术团队几乎支持了滴滴全部业务板块客服系统的诉求,面对多样性、逻辑变动快的业务场景,传统的面向场景编程成本高且周期长。所以咱们建设了线上配置化的运营系统,让运营、产品同窗可以经过画流程图的方式变动线上的业务逻辑,好比用户电话进线时的互动式语音应答、人工客服在处理用户进线时的标准做业流程、用户自助解决问题的 H5 页面配置系统等千人千面的应用场景。vue

其次,各业务系统虽然都须要应用流程可视化技术,但需求各不相同。有的对流程图的要求比较简单,图的数据格式也简单,而有的须要按照 BPMN 的规范来绘制流程图,对于定制化的要求较高。咱们调研了市面上相关的框架 (BPMN.js、X六、Jsplumb、G6-editor),均存在不知足的场景,技术栈统一的成本很高。具体表如今:node

  1. BMPN.js、Jsplumb 的拓展能力不足,自定义节点支持成本很高;只能全量引入,各系统没法按需引入
  2. 与后端配套的流程引擎适配,成本较高。均不支持数据转换、不支持流程的校验等业务定制需求。
  3. 文档、示例不健全。X6 和 BPMN 的文档不健全,示例少(2020 初调研结论)

所以,咱们在 2020 上半年开启了 LogicFlow 的项目,支持各系统的流程可视化需求。react

LogicFlow 的能力和特性

LogicFlow 当前已具有了哪些能力呢,我会分两部分来介绍。git

快速搭建流程图编辑器

提供了一个流程图编辑所必需的各项能力,这也是 LogicFlow 的基础能力:程序员

  • 图的绘制能力。基于 SVG 来绘制形状各异的节点和线,并提供了基础的节点(矩形、圆形、多边形等)和线(直线、折线、曲线)
  • 各种交互能力,让图动起来。根据节点、线、图的各种鼠标事件(hover、点击、拖拽等)作出反应。好比节点拖拽、拖拽建立连线、线的调整、双击节点编辑文本等
  • 提高编辑效率的能力。提供网格、对齐线,上一步、下一步,键盘快捷键,图放大缩小等配套能力,帮助用户提高编辑效率
  • 提供了丰富的 API ,宿主研发经过 API 传参调用和监听事件的方式,与 LogicFlow 完成交互

经过以上能力,前端研发能够低成本、快速的搭建起流程可视化的应用,提供流畅的产品交互。下面是经过 LogicFlow 内置的节点和配套能力,作的流程图示例:github

example1

基于业务场景拓展

当基础能力没法知足业务需求的时候,便须要基于业务场景拓展。这也是 LogicFlow 能支持客服侧多个系统的关键所在。算法

  • 设置图上全部元素的样式,好比各类节点、线、锚点、箭头、对齐线的大小颜色等,知足对前端样式调整的需求
  • API 拓展。支持在 LogicFlow 上注册自定义的方法,好比经过 API 拓展提供图片下载的方法
  • 自定义节点、线。内置的矩形、圆形等图形类节点每每没法知足实际的业务需求,须要定义具备业务意义的节点。LogicFlow 提供了 的方式让用户定制具备自定义图形、业务数据的节点,好比流程审批场景中的 “审批” 节点
  • 拓展组件。LogicFlow 在 SVG 图层上提供了 HTML 层和一系列坐标转换逻辑,并支持在 HTML 层注册组件。宿主研发能够经过 LogicFlow 的 API,基于任何 View 框架开发组件,好比节点的右键菜单、控制面板等
  • 数据转换 adapter。LogicFlow 默认导出的图数据不必定适合全部业务,此时能够经过 adapter API,在图数据从 LogicFlow 输入、输出的时候作自定义转换,好比转换成 BPMN 规范的图数据
  • 内置部分拓展能力。基于上述拓展能力,咱们还单独提供了 lf-extension 的包,用来存放客服业务下沉淀出的具备通用性的节点、组件等,好比面向 BPMN 规范的节点和数据 adapter,默认菜单。注意 lf-extension 能够单独安装,并支持按需引入

基于上述拓展的能力,前端研发可以根据实际业务场景的需求,灵活的开发出所需的节点、组件等。下面有两个基于 LogicFlow 拓展能力作出的流程图:编程

BPMN:小程序

图片:bpmn

审批流程:

图片: 审批流

定位对比

dingwei1

上图是经过横纵两个维度来对比目前你们耳熟能详的几个开源框架,以了解 LogicFlow 的定位。横轴是该框架在图可视化能力的丰富程度,纵轴越靠上则表明这个框架在业务流程应用上的成熟度越高,初次部署的开发成本越低。 让咱们分别来介绍一下这几个框架:

  • activiti 做为工做流引擎提供了先后端的解决方案,简单二次开发就能够部署一套业务流程的管理平台
  • Bpmn.js:基于 BPMN2.0 规范,设计的流程图编辑器
  • G6:antv 旗下专一图形可视化,各种分析类图表。好比生态树、脑图、辐射图、缩进图等等
  • X6:图编辑引擎,核心能力是节点、连线和画布。不只支持了流程图,还有 Dag 图、ER 图

LogicFlow 的定位在上图的 Bpmn.js 和 X6 之间,填补中间的空白。核心提供了流程图的编辑器,而且经过拓展能力来支持 BPMN 等规范所需的流程节点和数据格式,以知足当前业务下的现状。

实现原理和架构

总体架构图

图片: lfjk

核心包 @logicflow/core 提供了流程图编辑器基础的能力,右边的 @logicflow/extension 是基于 @logicflow/core 的拓展性开发的插件。

流程图编辑器的设计方案

主要介绍一下实现流程图编辑器重要的选型和方案设计。

图渲染方案

前端绘制图形无非就是 HTML + CSS、Canvas、Svg 三种方式,咱们综合作了一下对比,列出了相应的优劣势:

bijiao1

在流程图的场景下,不须要渲染大量的节点(最多几千个元素),对于动画的诉求也不高。Svg 基于 DOM 的特性会更适合咱们,一个是学习成本和开发成本更低,另外一个是基于 DOM 能够作的拓展也更多。不过 Svg 标签内部并不支持插入其余好比 div 这种标签,因此在实现某些功能的时候,都须要结合其余 HTML 标签。

因此最终咱们选择使用 HTML + Svg 来完成图的渲染,Svg 负责图形、线的部分,HTML 来实现文本、菜单、背景等图层

模块抽象

基于上述方案,下一步咱们要作的是对实现一张流程图作分类和抽象。

图片: mkcx

经过上图:

  • 首先咱们构建了多个图层来承担不一样的职责,以方便实现功能和能力拓展。最上层的是 Svg 图层,全部图形(节点、线、对齐线、outLine 等)均在 Svg 上渲染,也负责监听图上的各类事件。Svg 下层的分别是组件层,负责拓展 UI 组件;Grid 层,负责渲染网格;背景层,添加自定义的背景。
  • Shape 的职责主要是基于 Svg 对图形渲染的封装,提供默认样式、把用户传入的属性作转换等,主要包含 Rect、Circle、Ellipse、Polygon、Path、PolyLine、Text 等,方便 LogicFlow 内部复用,好比圆形节点和锚点都须要 Circle。
  • 基于 Shape,还实现了不少小元素,好比节点和线须要的锚点,好比线上的箭头等等。
  • 而 BaseNode、BaseEdge 则是节点和线通用能力的封装,聚合 shape、锚点、文本,还封装了对事件和样式的处理等。经过继承 BaseNode,传入 shape 咱们能够获得 RectNode、CircleNode 等可渲染的节点。

由于流程图是富交互或者说是重编辑的,有了这几个基础的模块,接下来要作的就是富交互的方案设计,即用户在图上作的任何操做都要给出响应。好比我触发一个节点的拖拽,那关联的线可能须要跟着动,还能识别出在某个水平线上有没有其余节点(对齐线)。

MVVM + Virtual DOM

首先咱们考虑到整个图编辑器具有不少状态存储,而且要实现编辑图上各模块的响应就必需要有状态的通讯能力。第二若是要实现相似 redo/undo 这类功能,那整个图就必定须要根据数据得出渲染,即 fn(state) => View ,比较好的方式就是经过 Model 来驱动 View。

最终咱们选择基于 MVVM,这个普遍被应用于当前前端工程中的设计模式来构建 LogicFlow 的图编辑器,定义图的 View 和 Model 层,使工程代码具有必定的解耦。与此同时,引入 Mobx 来实现咱们的状态管理、数据响应的能力,一张图基于一份 Model 作状态的通讯。此外,考虑 Mobx 的另外一个缘由是:只要我想,那就能够作到最细颗粒度的数据绑定(观测),能够减小不必的渲染。

如下是 LogicFlow 图编辑器的 MVVM 示意图: 图片: mvvm

经过上图能够看到,View 层(图、节点等)经过数据绑定,会在 Model 发生变化以后作出响应/更新。前面咱们提到了关于图的渲染咱们是基于 Svg + HTML 实现的,那要作 View 层的更新无非就是命令式和声明式两个选择:

  • 命令式。好比 jQuery 的 api,$('.rectNode').attrs({x: 1, y: 2}),像这种方式操做 DOM 代码其实比较繁琐,在重交互的场景下写的代码会比较冗余。虽然咱们最终找到了有一个库可以很方便的支持经过命令式的方式来绘图 —— antv/g
  • 声明式。好比 React/Vue 这类 View 框架,其中一个比较核心的能力就是作到了 state => UI ,经过声明式的方式来构建 DOM,只要状态发生变化,那 UI 就更新

除了考虑到命令式在操做 DOM 的场景下写代码会比较繁琐以外,还有一个缘由就是操做 DOM 的成本问题,在基于 State 更新 UI 的设计下,咱们天然而然想到了引入 Virtual DOM 来解决某些场景下的更新效率,这也能够必定程度上弥补「基于 Svg 渲染图形」可能形成的渲染性能问题。

总之,选择 MVVM 的设计模式并引入 Virtual DOM,最根本的两个缘由即是提高咱们图编辑器场景下的开发效率,以及在 HTML + Svg 的图渲染方案下,能够追求更好的性能表现

咱们与 X6 作了一次渲染时的性能比较,在相同的运行环境下,分别测出 LogicFlow 和 X6 在不一样量级的节点/线下,渲染出流程图的时间,理论上渲染时间越短,性能表现越好。

对比1

对比2

经过上述表格,咱们测算出 LogicFlow 在初始渲染速度上是优于 X6 的,而且这尚未开启LogicFlow 的按需加载功能,也验证了咱们的技术选型。你也能够在示例页进行测试: yhlchao.github.io/LF-VS-Other…

事件系统

介绍了在 “状态” 和 “响应” 咱们作的设计,那要收集到用户的各种 “操做” 并及时上报和冒泡,就须要一套事件系统。最主要的就是复用和统一上报。

图片: Event

复用即怎么保证全部节点和线都能具有默认的事件回调,以及针对复琐事件(拖拽)的处理逻辑如何共用。

  • Behavior。针对复琐事件的处理,咱们作了 function 和 class 形式的封装,好比 Drag 是经过 mousemove、down、up 来模拟 h5 的 dragEnter、dragOver、dragEnd 和 drop 事件,DnD 则是经过抽象 dragsource 和 droptarget 两个实体来实现 drag 和 drop 的交互,好比拖拽建立节点
  • 在前文模块抽象章节提到了内部有 BaseNode 和 BaseEdge 这样的抽象,内置节点和自定义的节点都经过继承基类来得到通用的能力,因此 LogicFlow 内部默认的事件回调实际是经过继承来复用的
  • EventCenter。经过事件总线作统一上报,把内部捕获到的全部用户行为事件,按照必定的规范和格式emit(ev, args)都上报到 EventCenter,最终冒泡到 LogicFlow 类,由 LogicFlow 类统一跟宿主交互。此外,图编辑器内任何地方也均可以经过 EventCenter 作事件的触发和监听

工具中心

工具中心的定位是解决某类特定问题的 utils,好比上面提到的 Behavior(复琐事件的封装) 和 EventCenter。此外,在图编辑的过程当中,若是要实现比较好的交互效果,实际有不少复杂的计算逻辑要处理。

  • 坐标系。浏览器的 clientX、clientY 坐标系,以及 Svg 图自己的坐标系,当出现图的缩放和平移的时候,两个坐标系显然是不一样的,那如何作坐标系的转换。

  • Algorithm。是专门经过几何、算法来处理可视化的一些问题。好比:当一个节点在同一方向有多条折线连出的时候,如何作路径的合并以展现起来更美观,以下

    图片: shili1

    如何计算出一根线到一个图形的切点,以达到线能够链接图形非锚点的位置,以下图

    图片:shili2

  • History,主要提供 redo 和 undo 的能力。经过两个栈来存储 undos 和 redos,并限制最大长度,得益于 MVVM 的设计模式,能方便的作数据变化的观测和 Model 驱动 View。

可扩展性

介绍完流程图编辑器的设计方案,如今来介绍 LogicFlow 的另外一个重要特性,关于拓展性方面的设计。在程序世界中,小到一个 function,一个服务,再到一个开发框架 react,小程序开发框架,大到一个 Chrome 类的应用平台,都具有本身的可扩展性,这也是软件发展过程当中要考虑的一种设计选择。对于 LogicFlow,是解决某个领域问题的开发框架,首先 API 要具有可扩展性;此外 LogicFlow 还提供了视图层,在 View 部分应该可以让用户作二次开发。这两个扩展的方向肯定以后,最主要的仍是结合业务需求,要能知足当前和将来一段时间内预见的业务场景,但也不能过分设计。

API 上的设计

首先,LogicFlow 在面向用户使用这一层,彻底是基于面向对象的设计模式封装的,最大的好处是几乎每一个程序员都熟悉它的使用,使用成本低。经过下面初始化方式即可以了解。

const lf = new LogicFlow({ // 实例化 lf 对象
  container: document.querySelector('#graph'), // 获取渲染容器
  width: 700,
  height: 600,
  tool: {
    menu: true,
    control: true,
  },
  background: {
    color: '#F0F0F0'
  },
  grid: {
    type: 'dot',
    size: 20,
  },
});
lf.render({ nodes: [], edges: []}); // 在界面上渲染视图
复制代码

经过 class LogicFlow,用户实例化一次便获得一个流程图的实例,状态也是私有的,各类使用方法经过 lf 的实例调用便可。 关于 API 拓展的设计总结来看:

  1. 面向对象的设计模式, LogicFlow 内部作好封装,用户能够作继承、重写接口/方法
  2. 方法的设计。首先是要有固定类型的输入和输出。此外,LogicFlow 也提供了相似于 extends 的方法,经过 LogicFlow.use(fn) 在原型上拓展方法
  3. 经过观察者的模式作通讯,即提供 on 方法供宿主订阅各种内部事件
  4. 图的数据可定制。不管是一个节点、线有哪些自定义的业务属性,仍是流程图要导出什么样的数据,都应该可以定制。

插件化

View 层的拓展性,除了用户可以定制展示方式以外,最重要的是插件化,由于在流程可视化这条路上,不一样的业务场景下须要的能力不尽相同,LogicFlow 很难作到支持全部的场景,因此提供好的插拔能力,让用户二次开发是比较好的选择。目前,在 UI 界面上,咱们开放了两个能力:

  1. 节点和线支持二次开发,即自定义节点、线
  2. 可开发 UI 组件注册到 LogicFlow 的组件画布内

基于插件化的思路,咱们已经支持了不一样的业务系统,并在这个过程当中把一些稍微通用的能力沉淀出来,并封装到 lf-extension 包,好比用来支持 BPMN 规范的节点。目前 extension 内的拓展主要分了四类:UI 组件、自定义节点、API、adapter。

将来规划

  1. API 的易用性和丰富程度。具体的功能 scope 除了咱们当前的迭代计划(详见 github 仓库的 project),还会根据用户的需求排出优先级后加入进来,也但愿你们多多提意见和需求。这个方向的基调是保持 LogicFlow 流程可视化的定位,把 core 的 API 丰富,extension 的能力加强
  2. 更完善的文档和示例。主要是文档易读、完善,可以有完整的示例和代码,供开发者 copy paste 代码,目前示例只有 react 版,2021.4 以前会增长 vue 版的示例
  3. 不只是流程可视化库,指望提供整套解决方案。LogicFlow 只解决了前端流程图编辑的技术问题,但关于图数据的定义,流程最终如何被执行,还须要一个配套的流程引擎。目前,关于「流程引擎」咱们团队也有相应的解决方案 —— turbo(Java 版已开源:github.com/didi/turbo) 咱们会把 LogicFlow 和 turbo 作成端到端的解决方案,并提供完整的应用示例。此外,Nodejs 版的引擎也在规划中,你们拭目以待。

最后

相信你对 LogicFlow 已经有一个大概的认识了,若是在你负责的业务中也有流程可视化的诉求,而且有较高的拓展性需求,那 LogicFlow 会是一个好的选择。对于 LogicFlow 技术自己的实现细节、对于类似业务的探讨也都欢迎你们来交流。咱们后续会有更多的文章介绍 LogicFlow 在技术设计细节以及咱们对于可视化、业务流程、逻辑编排等领域的一些思考,尽情期待。

相关文章
相关标签/搜索