# jsPlumb 6.x 快速入门

# 1. 介绍

本文介绍 jsPlumb 6.x 社区版的基本使用

涉及的示例代码,请参考 https://github.com/forwardNow/flowchart-editor/tree/jsplumb-guide (opens new window)

# 1.1. 什么是 jsPlumb

在网页上基于 SVG 绘制流程图的 JS 库

# 1.2. 特点

节点使用 div + css 绘制,

连线使用 jsPlumb 绘制,

相对 canvas 来说要简单与灵活。

# 1.3. 安装

npm install @jsplumb/browser-ui

## "@jsplumb/browser-ui": "^6.2.10",

# 2. 基础

英文 中文 说明
jsPlumbInstance 实例 jsPlumb 实例
Node/Element 节点 一根线连接两个节点(源节点 连接 目标节点)
Connector 连线 线
Endpoint 端点 线两端的点 称为 端点
Anchor 锚点 定义 连线 与 节点 相连的位置
Overlay 装饰 连线上的文本或箭头等

# 2.1. jsPlumbInstance

# 2.1.1. 概念

说明:

  • jsPlumb 实例

# 2.1.2. 创建

API:

  • function newInstance(options?: Options): BrowserJsPlumbInstance;

示例:

import { newInstance } from "@jsplumb/browser-ui"

const jsPlumbInstance = newInstance({
  container: document.getElementById('#box'),
});

# 2.1.3. Options

Options 为 BrowserJsPlumbDefaults

interface Options {
    // 容器,节点所在的容器,该元素需要设置 `position: relative`
    container: HTMLElement,

    // 节点是否可拖拽,默认 true
    elementsDraggable?: boolean;
    
    // 拖拽配置
    dragOptions?: {
      // 限制节点拖动区域
      containment?: 'notNegative' | 'parent' | 'parentEnclosed'; // 'parent' - 父元素内
      
      // 网格
      grid?: {
        w: number;
        h: number;
        thresholdX?: number;
        thresholdY?: number;
      };
      
      start?: (params: DragStartEventParams) => void;
      drag?: (params: DragEventParams) => void;
      stop?: (params: DragStopEventParams) => void;
      beforeStart?: (params: BeforeStartEventParams) => void;
      cursor?: string;
      zIndex?: number;
      trackScroll?: boolean;
      filter?: string;
    };

    // 连接是否可以断开,默认 true
    connectionsDetachable?: boolean;
    
    // 端点最多能拉出几条连线 ,-1 为不限制,默认 1
    maxConnections?: number;

    // allowNestedGroups
    // anchor
    // anchors
    // connectionOverlays
    // connector
    // endpoint
    // endpointOverlays
    // endpoints
    // endpointStyle
    // endpointStyles
    // endpointHoverStyle
    // endpointHoverStyles
    // hoverClass
    // hoverPaintStyle
    // listStyle
    // paintStyle
    // reattachConnections
    // scope


    /**
     * Specifies the CSS selector used to identify managed elements. 
     * This option is not something that most users of jsPlumb will need to set.
     */
    managedElementsSelector?: string;
    
    /**
     * Defaults to true, indicating that a ResizeObserver will be used, where available, to allow jsPlumb to revalidate elements
     * whose size in the DOM have been changed, without the library user having to call `revalidate()`
     */
    resizeObserver?: boolean;
}

# 2.1.4. 销毁

jsPlumbInstance.destroy()

# 2.1.5. 更改默认配置

API:

  • jsPlumbInstance.importDefaults(d: JsPlumbDefaults<T["E"]>): JsPlumbInstance;

说明:

  • 配置项与 newInstance 一致

# 2.2. Node(节点)

# 2.2.1. 概念

说明:

  • 连线相连的两个元素,称为节点
  • 连线的开始节点,称为源节点
  • 连线的结束节点,称为目标节点

分类:

  • 源节点(source)
  • 目标节点(target)

# 2.2.2. 注册节点

API:

  • jsPlumbInstance.manage(element: Element, internalId?: string): ManagedElement<Element>;

说明:

  • 将 节点 纳入 jsPlumb 管理,这样节点可以拖拽移动了
  • 被 jsPlumb 管理的节点,都有一个内部 ID,称为 managedId 或 internalId
  • 节点要设置 position: absolute;

示例:

<template>
  <div class="stage-demo" ref="stage" >

    <div class="fc-node fc-node-circle" ref="sourceNode">
      <div class="fc-node-inner">
        <div class="fc-node-text">起止符号</div>
      </div>
    </div>

    <div class="fc-node fc-node-rectangle" ref="targetNode" style="left: 200px;">
      <div class="fc-node-inner">
        <div class="fc-node-text">任务内容</div>
      </div>
    </div>

  </div>
</template>
<script>
import {
  DEFAULT_KEY_CONTAINER, // "container"
  newInstance,
} from '@jsplumb/browser-ui';

export default {
  mounted() {
    const stageElement = this.$refs.stage;
    const sourceElement = this.$refs.sourceNode;
    const targetElement = this.$refs.targetNode;

    const jsPlumbInstance = newInstance({
      [DEFAULT_KEY_CONTAINER]: stageElement,
    });

    jsPlumbInstance.manage(sourceElement);

    jsPlumbInstance.manage(targetElement, 'managed-id-123');
  },
};
</script>

# 2.2.3. 节点是否可拖拽

说明:

  • 有两种方式可以设置节点是否可以拖拽
  • 默认情况,节点被管理后,就可以可以拖拽

方式一:

  • 创建实例时,传入 elementsDraggable 选项

  • 示例:

    <script>
    import {
      DEFAULT_KEY_CONTAINER, // "container"
      newInstance,
    } from '@jsplumb/browser-ui';
    
    export default {
      mounted() {
        const jsPlumbInstance = newInstance({
          // 默认值为 true
          elementsDraggable: true,
        });
      },
    };
    </script>
    

方式二:

  • 更改 jsPlumbInstance.elementsDraggable 的值即可

  • 示例:

    // 节点 可以拖拽
    jsPlumbInstance.elementsDraggable = true;
    
    // 节点 不可拖拽
    jsPlumbInstance.elementsDraggable = false;
    

# 2.2.4. 获取元素的内部ID

API:

  • jsPlumbInstance.getId(element: T["E"], uuid?: string): string;

# 2.2.5. 根据内部ID获取元素

API:

  • jsPlumbInstance.getManagedElement(id: string): T["E"];

# 2.2.6. 删除元素的所有连线

API:

  • jsPlumbInstance.deleteConnectionsForElement(el: T["E"], params?: DeleteConnectionOptions): JsPlumbInstance;

说明:

  • 删除连接到该元素的所有连线

# 2.2.7. 删除节点(HTML元素)

API:

  • el.parentNode?.removeChild(el);

# 2.3. Connector(连线)

# 2.3.1. 概念

说明:

  • 连接节点的线

分类:

  • 流程线 'Flowchart'
  • 直线 'Straight'
  • 贝塞尔曲线 'Bezier'
  • 状态机 'StateMachine'

# 2.3.2. 连接两个节点

API:

  • jsPlumbInstance.connect(params: ConnectParams<T["E"]>, referenceParams?: ConnectParams<T["E"]>): Connection;

示例:

import { LabelOverlay } from '@jsplumb/browser-ui';

jsPlumbInstance.connect({
  source: document.getElementById('#sourceNode'),
  target: document.getElementById('#targetNode'),
  anchors: ['Right', 'Left'],
  overlays: [
    {
      type: LabelOverlay.type,
      options: {
        label: '这是一个连接线'
      },
    },
  ],
});

# 2.3.3. 是否在拖拽连线

说明:

  • 通过 jsPlumbInstance.currentlyDragging 判断是否在拉线

# 2.4. Endpoint(端点)

# 2.4.1. 概念

说明:

  • 连线两端的点,称为端点

# 2.4.2. 显示隐藏

说明:

  • 通过 CSS 样式控制端点的显示和隐藏

示例:

.box {
  .jtk-endpoint {
      visibility: hidden;
    }
  
  &.endpoint-visible {
    visibility: visible;
  }
}

# 2.5. Anchor

# 2.6. Overlay (TODO)

# 3. 实战 (TODO)

# 4. 笔记

事件:

import { newInstance, EVENT_CONNECTION_CLICK } from "@jsplumb/browser-ui"

const instance = newInstance()

instance.bind(EVENT_CONNECTION_CLICK, (connection: IJsPlumbConnection, event: PointerEvent) => {
  console.log(connection);
});

API:

// get managedId
jsPlumbInstance.getId(el) // e015b118-09b6-4a3f-a07e-d3770cac4f4e

// get element by managedId
jsPlumbInstance.getManagedElement(managedId)

// get all connections
jsPlumbInstance.getConnections()

// 删除连线
jsPlumbInstance.deleteConnection(connection: Connection)

jsPlumbInstance.manage(el, managedId)

jsPlumbInstance.addEndpoints(el, endpoints)

jsPlumbInstance.connect(el, endpoints)

jsPlumbInstance.addOverlay(connection, overlay)

path:

// ts/browser-ui-renderer/svg-element-connector.ts

// paintSvgConnector()
//  instance.getPathData(connector)

jsPlumbInstance.getPathData(connection.connector) // M 0 0 L 30 0 L 240 0 L 450 0 L 480 0 

# 5. 参考

本章目录