六、使用jsPlumb实现流程图--Overlays使用

一、Overlay的功能
叠层(Overlay)可以是任意的DOM元素,用于叠加在Connection或Endpoint元素上--绝大部分都是用于叠加在线条上。jsPlumb把Overlay分为了五类:ArrowLabelPlainArrowDiamondCustom
除了CustomLabel类型,其他三类就是jsPlumb提供的可以直接使用的图形;Label类型可以直接提供字符串文案,jsPlumb就可以生成对应的Overlay并显示;而Custom类型就是自定义DOM。

二、Overlay的使用
创建Overlay有多种方式:
创建连线时创建Overlay

jsPlumb.value.connect({
    source: node1.value,
    target: node2.value,
    anchors: ['Right', 'Left'],
    connector: StraightConnector.type,
    overlays: [
      {
        type: 'Arrow',
        options: {
          location: 1,
        },
      },
      {
        type: 'PlainArrow',
        options: {
          location: 0.25,
        },
      },
      {
        type: 'Diamond',
        options: {
          location: 0.75,
          id: 'diamondOverlay'
        },
      },
      {
        type: 'Label',
        options: {
          label: 'myLabel',
          location: 0.5,
        },
      },
    ],
  });

其中的location属性就是设置Overlay在线条上位置。如果location在[0,1]之间,代表的就是长度比例,例如0.5=中间,0.25=起始点1/4处,0.75=目的点1/4处,1=目的点;如果location>1,就是到起始点的距离px。
属性id就是给Overlay一个全局唯一ID,后续可以通过这个ID查询到该Overlay,从而进行操作--删除/更新等。

另外就是在创建Endpoint的时候可以使用connectorOverlays参数来创建Overlay:

const endpoint3 = jsPlumb.value.addEndpoint(node3.value, {
    source: true,
    endpoint: 'Rectangle',
    anchor: AnchorLocations.Right,
    connectorOverlays: [
      { type: 'PlainArrow', options: { location: 1 } },
      { type: 'Label', options: { label: 'From Node3', id: 'node3-overlay' } },
    ],
  });
  const endpoint4 = jsPlumb.value.addEndpoint(node4.value, {
    target: true,
    endpoint: 'Dot',
    anchor: AnchorLocations.Left,
  });

但是这样配置的Overlay不是立刻创建并显示的,而是要等到以endpoint3为起始点进行连线的时候才会出来,也就是在连线的同时创建出Overlay。

并且如果把connectorOverlays配置到只能作为目的点的Endpoint的话是没用的。connectorOverlays只能在source=true时才会在连线时生效。
官方文档中说addEndpoint的参数中可以使用overlays来配置,实际使用中是不能使用overlays参数的,只有connectorOverlays可以使用。

还有就是jsPlumb的线条实例可以直接调用addOverlay来创建

  const conn_5_6 = jsPlumb.value.connect({
    source: node5.value,
    target: node6.value,
    anchors: ['Top', 'Top'],
    connector: 'Flowchart',
  });
  conn_5_6.addOverlay({
    type: 'PlainArrow',
    options: { location: 1 },
  });

三、Overlay的配置
各种类型的Overlay都有一个配置参数就是location,指定Overlay所处的位置。而PlainArrowDiamond都是一种Arrow,就是某一项参数--foldback的配置值不同而已。
Arrow有以下配置参数:

  • width:设置箭头的宽度
  • length:设置箭头的长度。结合width参数就可以用来设置箭头的大小。
  • location: 指定位置
  • direction: 指定箭头的方向,取值只能是1或-11代表向前(指向目的点), -1代表向后(指向起始点)。
  • foldback: 设置一个数值,用于控制箭头的形状。
    前四个参数的含义都很明确也很好理解,关于foldback参数,用图解释:

    图中的红色点,就是foldback指定的数值。Arrow类型foldback=0.623PlainArrow类型foldback=1Diamond类型foldback=2。其实本质就是一个四边形,三个点固定,第四个点可以沿着对角线移动,从而可以形成不同的形状。
    如果觉得jsPlumb提供的箭头不好看,就可以微调这个参数的值。因此PlainArrowDiamond出了foldback参数,其余可配参数与Arrow一致。

Label类型
Label类型的Overlay并不是图形,而是文案。因此配置项不同:

  • label:指定文案内容。
  • cssClass:配置Overlay样式。(官方文档中说建议使用labelStyle配置,但没有找到哪里可以使用labelStyle)
  • location:指定Overlay的位置。
  const conn_7_8 = jsPlumb.value.connect({
    source: node7.value,
    target: node8.value,
    connector: 'Flowchart',
    anchors: ['Top', 'Top'],
    overlays: [
      {
        type: 'Label',
        options: {
          location: 0.3,
          label: 'Label1',
          cssClass: 'label-e1',
          id: 'lab1',
        },
      },
      {
        type: 'Label',
        options: {
          location: 0.6,
          label: 'Label2',
          labelStyle: { color: 'blue' },
          id: 'lab2',
        },
      },
    ],
  });
  .label-e1 {
    color: red;
    padding: 4px;
    background-color: blue;
    height: 40px;
  }

官方文档中写的,通过Overlay实例可以调用setLabel()和getLabel()方法,在实际jsPlumb的overlay.d.ts源代码中,Overlay实例并没有提供这两个API。不过Connector和Endpoint实例提供了getLabel/setLabel方法,因此如果需要动态获取/变更overlay的文案,可以通过Connector/Overlay实例来实现。

由于在连线上创建Label是非常常用的,jsPlumb提供了更加简便的创建Label的方式:

  const conn_7_8_1 = jsPlumb.value.connect({
    source: node7.value,
    target: node8.value,
    connector: 'Flowchart',
    anchors: ['Bottom', 'Bottom'],
    label: 'label by connect',
  });

Custom
自定义Overlay,可以将Overlay设置成按钮/下拉框/输入框等任意元素。

import {
  newInstance,
  BrowserJsPlumbInstance,
  AnchorLocations,
  StraightConnector,
  Component,
} from '@jsplumb/browser-ui';

jsPlumb.value.connect({
    source: node9.value,
    target: node10.value,
    anchors: ['Top', 'Top'],
    connector: 'Flowchart',
    overlays: [
      { type: 'Arrow', options: { location: 1 } },
      {
        type: 'Custom',
        options: {
          create: (component: Component) => {
            console.log(component);
            const d = document.createElement('span');
            d.setAttribute('class', 'line-btn');
            d.addEventListener('click', (event: MouseEvent) => {
              event.stopPropagation();
              alert('btn click');
            });
            d.innerHTML = '按钮';
            return d;
          },
          location: 0.5,
        },
      },
    ],
  });
  .line-btn {
    color: white;
    background-color: #40bdec;
    font-size: 12px;
    border-radius: 4px;
    padding: 3px;
    cursor: pointer;
  }


配置项create为一个方法,方法最后需要返回一个DOM即可,不管是简单的还是复杂的。

四、Overlay的操作
除了Overlay的创建,还有一些其他的API操作,例如显示/隐藏移除。通过持有Overlay实例或Connection实例就可以调用这些方法:

  // 隐藏所有overlay
  conn_7_8.hideOverlays();
  // 显示所有overlay
  conn_7_8.showOverlays();

  // 通过线条实例来显示/隐藏overlay
  conn_7_8.hideOverlay("lab1");
  conn_7_8.showOverlay("lab1");

  // 通过overlay实例来显示/隐藏label
  const lab2Overlay = conn_7_8.getOverlay("lab2");
  lab2Overlay.setVisible(false);
  lab2Overlay.setVisible(true);

官方文档中写的Overlay实例有hide()和show()方法,实际代码中并没有这两个API

五、总结
文章中的完整演示代码地址在此,jsPlumb中的几个关键概念的基本使用方式就已经介绍完了,使用这些基本用法就可以创建一个简单的流程图功能,但是还不足以实际完成一个项目。接下来会介绍常用的事件与拦截器。

posted @ 2024-03-25 11:38  Bencakes  阅读(551)  评论(0编辑  收藏  举报