likes
comments
collection
share

实现流程编排设计器的心路历程

作者站长头像
站长
· 阅读数 45

接上回《「AntV」使用AntV X6实现流程编排设计器》一文说到,流程编排设计器的实现方案是将低代码引擎和AntV X6作为画布相结合。

为什么会有这样的想法?

可行性

起因是业务中有用到低代码引擎的场景,它的交互形式、页面结构正好符合流程编排设计器的诉求。同时,在阅读低代码引擎文档时,发现设计原理->渲染模块设计->模拟器介绍中有如下介绍:

基于以上思考,我们通过基于沙箱隔离的模拟器技术来实现了多运行时环境(如 React、Rax、小程序、Vue)、多模式(如流式布局、自由布局)、多场景(如页面编排、关系图编排)的 UI 编排。通过注册不同的运行时环境的渲染模块,能够实现编辑器从 React 页面搭建到 Rax 页面搭建的迁移。通过注册不同的模拟器画布,你可以基于 G6 或者 mxgraph 来做关系图编排。你可以定制一个流式布局的画布,也可以定制一个自由布局的画布。

综上可见,使用AntV X6作为画布和低代码引擎结合方案的可行性是没有问题。

那么接下来就是实践了,因为

实现流程编排设计器的心路历程

于是乎走上了阅读源码,自己探索的道路。

埋头苦干

通过阅读源码,并借鉴Lowcode Engine Vue 渲染器及适配器实现的实现思路,期望也能够基于BuiltinSimulatorRenderer这个桥梁,通过结合Antv X6, 实现Lowcode Engine BPMN(X6)的伟大构想。

不过在近一个月的大量研究、实践、测试后,仅仅是完成了画布的渲染,正常编排交互无法得以解决。

React和Vue的画布(渲染器)是运行在iframe中,存在事件通信等一系列机制。而AntV X6如果也运行在iframe中,本身的拖拽等事件和宿主拖拽等事件存在着各种各样的冲突,即使在尝试修改了低代码引擎的部分源码后,也没有能够完全解决。

在实践过程中,也提过相关的issue,寻求官方解决方案。当时得到的回答是内部方案还在打磨中,并未开源。(PS: 不过在自己项目发布没多久,官方方案图编排扩展就开源了)

虽然失败了,但是也充分学习了画布相关的源代码,了解了其实现原理。

贴一张官方的模拟器架构图,「模拟器Host进程」和iframe中的「模拟器Renderer进程」通信

实现流程编排设计器的心路历程

睡醒再干

俗话说,在哪里跌倒,就在哪里睡一觉。

睡醒之后,再次寻求解决方案。既然基于底层API搞不了,去上层瞅瞅呢?

低代码引擎本身只包含了最小的内核,而我们所能看到的设计器上的按钮、面板等都是插件提供的。插件是组成设计器的必要部分。通过定制插件,在和低代码引擎解耦的基础上,我们可以和引擎核心模块进行交互,从而满足多样化的功能。

显然画布也不例外。如果把原画布移除,添加自己实现的X6画布,是否可行呢?你还真别说,有一种重见天日,恍然大明白的感觉。

注册默认画布

如下是低代码引擎中注册画布面板的源码实现:

import { IPublicModelPluginContext } from '@alilc/lowcode-types';
import DesignerPlugin from '@alilc/lowcode-plugin-designer';

// 注册默认的面板
export const defaultPanelRegistry = (editor: any) => {
  const fun = (ctx: IPublicModelPluginContext) => {
    return {
      init() {
        const { skeleton, config } = ctx;
        skeleton.add({
          area: 'mainArea',
          name: 'designer',
          type: 'Widget',
          content: <DesignerPlugin
            engineConfig={config}
            engineEditor={editor}
          />,
        });
      },
    };
  };

  fun.pluginName = '___default_panel___';

  return fun;
};

export default defaultPanelRegistry;

自定义X6画布面板

如下是自定义X6画布的源码实现:

import { IPublicModelPluginContext } from "@alilc/lowcode-types";
import DesignerView from "@/components/DesignerView";

const BuiltinPluginRegistry = (ctx: IPublicModelPluginContext) => {
  return {
    name: "builtin-plugin-registry",
    async init() {
      const { skeleton } = ctx;
      
      // 移除默认的画布
      skeleton.remove({
        name: "designer",
        area: "mainArea",
        type: "Widget",
      });

      // 注册X6画布面板
      skeleton.add({
        name: "x6Designer",
        area: "mainArea",
        type: "Widget",
        content: DesignerView,
      });
    },
  };
};
BuiltinPluginRegistry.pluginName = "builtinPluginRegistry";

export default BuiltinPluginRegistry;

画布代码示例:

import React, { useRef } from "react";
import "./index.less";

export default () => {
  const containerRef = useRef(null);

  // 省略初始化画布代码

  return (
    <div className="lc-designer lowcode-plugin-designer">
      <div className="lc-project">
        <div className="lc-simulator-canvas lc-simulator-device-default">
          <div id="x6-container" ref={containerRef} />
        </div>
      </div>
    </div>
  );
};

拖拽

我们需要通过拖拽交互从组件库面板中拖动组件到画布中添加节点,使用到了AntV 独立的插件包@antv/x6-plugin-dnd来实现。

在低代码引擎中,有内置的拖拽引擎Dragon

为了后续研发能够顺利开展,在拖拽机制上并没有采用低代码引擎自带的方案。

结语

在开发过程中,我们难免会遇到了一些问题,一开始可能没有成功实现预期的方案,但这也是一种宝贵的经验。我们不应该放弃,而是要继续探索,寻找更好的解决方案。同时,也要学会从失败中汲取教训,不断优化自己的思路和方法,以达到更好的效果。

有时间可以再写写关于低代码引擎画布相关的源码阅读

转载自:https://juejin.cn/post/7252499099327692858
评论
请登录