# 自定义插件

LogicFlow提供了很多的插件,但是这些插件都是一些具有普适性的插件,不一定都符合业务需求。LogicFlow支持开发者基于自己的业务场景开发

# 插件的基础格式

class PluginCls {
  static pluginName = 'pluginName',
  constructor({ lf, LogicFlow }) {
    // do anything
  }
  render(lf, toolOverlay) {
    // do anything
  }
  destroy() {
    // do anythine
  }
}
  • 插件是一个类。
  • 这个类有个静态属性pluginName用于标识插件的名称。同名的插件在初始化lf实例的时候会覆盖。同时使用方可以通过lf.extension.插件名称获取插件这个类的实例。
  • 在初始化lf实例的时候,会同时初始化插件实例,此时会传入参数lfLogicFlow
  • lf渲染完成后,会调用插件实例的render方法(如有)。第二个参数domOverlay是表示LogicFlow Dom层的节点。插件开发者可以直接在这个节点插入html内容。
  • destroy是销毁插件是调用的方法。大多数情况下可以不写。

# 实现context-pad插件

下面实现一个context-pad示例,向大家介绍如何定义符合自己业务的插件。context-pad插件是一个点击节点后,在节点旁边出现可选的快捷操作,可以看做是左键点击出现的菜单。

# 增加插入选项方法

LogicFlow会将插件的实例以插件名称的形式挂载到lf.extension上,这样我们在class中的方法就可以用lf.extension.插件名称.插件方法调用了。

class ContextPad {
  /**
   * 设置通用的菜单选项
   */
  setContextMenuItems(items) {
    this.commonMenuItems = items;
  }
}

ContextPad.pluginName = "contextPad";

// 调用方法

lf.extension.contextPad.setContextMenuItems([
  {
    icon: "...",
    callback: () => {}
  }
])

# 监听节点被点击

在插件被初始化时,会将lf以参数的形式传递给插件,这时可以利用lf监听画布上发生的事件。

class ContextPad {
  constructor({ lf }) {
    lf.on("node:click", (data) => {
      this.showContextPad(data)
    })
  }
  showContextPad() {
    // ...
  }
}

# 在画布指定位置显示HTML内容

插件的render函数有两个参数,一个是lf, 第二个参数是toolOverlay, 也就是组件层。LogicFlow的画布是由多个图层组成,而组件层则是专门用来渲染自定义的组件。

LogicFlow的图分层

所以这里我们只需要将菜单插入到toolOverlay, 然后将其菜单移动到对应的位置即可。

class ContextPad {
  render(lf, toolOverlay) {
    this.toolOverlay = toolOverlay;
  }
  createMenu () {
    this.__menuDOM = document.createElement('div')
  }
  // 计算出菜单应该显示的位置(节点的右上角)
  getContextMenuPosition() {
    const data = this._activeData;
    const Model = this.lf.graphModel.getElement(data.id);
    let x;
    let y;
    if (Model.BaseType === "node") {
      x = data.x + Model.width / 2;
      y = data.y - Model.height / 2;
    }
    return this.lf.graphModel.transformModel.CanvasPointToHtmlPoint([x, y]);
  }
  showMenu () {
    const [x, y] = this.getContextMenuPosition();
    this.__menuDOM.style.display = "flex";
    // 将菜单显示到对应的位置
    this.__menuDOM.style.top = `${y}px`;
    this.__menuDOM.style.left = `${x + 10}px`;
    this.toolOverlay.appendChild(this.__menuDOM);
  }
}

# 完整示例