npm package: @knotx/plugins-connection-line
Description: Connectionline Plugin for Knotx
Author: boenfu
Latest version: 0.5.10

# @knotx/plugins-connection-line

连接线插件，为节点间连接提供拖拽式连接线功能。

## 安装

```bash
npm install @knotx/plugins-connection-line
```

## 基本概述

`@knotx/plugins-connection-line` 是 KnotX 框架的连接线插件，提供节点间的拖拽式连接功能。用户可以从节点的连接点拖拽出连接线，连接到其他节点或空白区域创建新节点。支持多选节点同时连接、自定义连接线样式和节点创建器。

## 实现原理

该插件通过 InteractJS 实现拖拽交互：

1. **连接点识别**：自动识别节点上的连接点（source/target）
2. **拖拽处理**：处理连接线的拖拽交互和视觉反馈
3. **连接创建**：支持连接到其他节点或空白区域创建新节点
4. **多选支持**：支持从多个选中节点同时拖拽连接线
5. **自定义创建器**：支持注册自定义的节点和边创建器

## 依赖插件

该插件依赖以下包：

- `@knotx/core` - 核心功能
- `@knotx/decorators` - 装饰器支持
- `@knotx/plugins-canvas` - 画布插件（peer dependency）
- `@knotx/plugins-selection` - 选择插件（peer dependency）
- `@knotx/jsx` - JSX 支持（peer dependency）
- `interactjs` - 交互库（peer dependency）
- `lodash-es` - 工具库
- `rxjs` - 响应式编程

## API 使用

### 基本使用

```typescript
import { ConnectionLine } from '@knotx/plugins-connection-line'

// 创建连接线插件实例
const connectionLine = new ConnectionLine()

// 在引擎中注册插件
engine.use(connectionLine)
```

### 配置选项

```typescript
const connectionLine = new ConnectionLine().init({
  allowCreateNodeOnBlankArea: true,
  edgeType: 'bezier',
  connectionLineClassName: 'custom-connection-line',
  connectionLineSVGAttributes: {
    stroke: '#2563eb',
    strokeWidth: '2',
    strokeDasharray: '5,5'
  },
  allowMultiDrag: true
})
```

### 连接点属性

```tsx
// 为节点添加连接点
function ConnectableNode({ node }) {
  const { getConnectHandleAttributes } = useKnotX().connectionLine

  return (
    <div>
      <div>{node.data.label}</div>
      <div
        {...getConnectHandleAttributes({
          nodeId: node.id,
          type: 'source',
          index: 0,
          className: 'my-connect-handle'
        })}
        style={{
          position: 'absolute',
          right: -5,
          top: '50%',
          transform: 'translateY(-50%)',
          width: 10,
          height: 10,
          borderRadius: '50%',
          backgroundColor: '#2563eb'
        }}
      />
      <div
        {...getConnectHandleAttributes({
          nodeId: node.id,
          type: 'target',
          index: 0
        })}
        style={{
          position: 'absolute',
          left: -5,
          top: '50%',
          transform: 'translateY(-50%)',
          width: 10,
          height: 10,
          borderRadius: '50%',
          backgroundColor: '#dc2626'
        }}
      />
    </div>
  )
}
```

### 注册自定义创建器

```typescript
// 注册自定义节点和边创建器
const unregister = connectionLine.registerCreator(({ sourceNodeIds, targetPosition }) => {
  if (targetPosition) {
    // 在空白区域创建新节点
    const newNode = {
      id: generateId(),
      type: 'default',
      position: targetPosition,
      data: { label: '新节点' }
    }

    const newEdges = sourceNodeIds.map(sourceId => ({
      id: generateId(),
      type: 'bezier',
      source: sourceId,
      target: newNode.id
    }))

    return {
      nodes: [newNode],
      edges: newEdges
    }
  }

  // 返回 undefined 使用默认创建逻辑
  return undefined
})

// 取消注册
unregister()
```

### 完整示例

```typescript
import { Engine } from '@knotx/core'
import { Canvas } from '@knotx/plugins-canvas'
import { ConnectionLine } from '@knotx/plugins-connection-line'
import { Selection } from '@knotx/plugins-selection'

const engine = new Engine()

// 注册依赖插件
engine.use(new Canvas())
engine.use(new Selection())

// 注册连接线插件
engine.use(new ConnectionLine().init({
  allowCreateNodeOnBlankArea: true,
  edgeType: 'bezier',
  connectionLineClassName: 'custom-connection-line',
  connectionLineSVGAttributes: {
    stroke: '#2563eb',
    strokeWidth: '2',
    strokeDasharray: '5,5',
    markerEnd: 'url(#arrowhead)'
  },
  allowMultiDrag: true
}))

// 注册自定义创建器
const connectionLinePlugin = engine.getPlugin('connectionLine')
connectionLinePlugin.registerCreator(({ sourceNodeIds, targetPosition }) => {
  // 自定义创建逻辑
  return {
    nodes: [/* 新节点 */],
    edges: [/* 新边 */]
  }
})
```

## 配置接口

### ConnectionLineConfig

```typescript
interface ConnectionLineConfig {
  /**
   * 是否允许连接到画布空白处并创建新节点
   * @default false
   */
  allowCreateNodeOnBlankArea?: boolean
  /**
   * 新创建的边的类型
   * @default 'bezier'
   */
  edgeType?: string
  /**
   * 临时连接线的类名
   */
  connectionLineClassName?: string
  /**
   * 临时连接线的SVG属性
   */
  connectionLineSVGAttributes?: Record<string, string>
  /**
   * 是否支持从多个选中节点同时拖拽连接线
   * @default true
   */
  allowMultiDrag?: boolean
}
```

### 插件数据接口

```typescript
declare module '@knotx/core' {
  interface PluginData {
    connectionLine: {
      isDragging: boolean
      registerCreator: (creator: (params: {
        sourceNodeIds: string[]
        targetPosition: { x: number, y: number } | undefined
      }) => ({
        nodes: Node[]
        edges: Edge[]
      }) | undefined | false) => () => void
      getConnectHandleAttributes: (params: {
        nodeId: string
        type: 'source' | 'target'
        index?: number
        className?: string
      }) => Record<string, string>
    }
  }
}
```

## 交互功能

### 连接线拖拽

- 从节点连接点开始拖拽
- 实时显示连接线预览
- 支持多选节点同时连接
- 自动边缘滚动

### 连接目标识别

- 自动识别有效的连接目标
- 连接点高亮显示
- 支持连接到空白区域创建新节点

### 连接线样式

- 支持自定义连接线样式
- 支持 SVG 属性配置
- 支持自定义 CSS 类名

## 文件目录结构

```
packages/plugins-connection-line/
├── src/
│   ├── connection-line.tsx   # 连接线插件主文件
│   └── index.ts             # 导出文件
├── dist/                    # 编译输出目录
├── CHANGELOG.md            # 变更日志
├── package.json            # 包配置
├── build.config.ts         # 构建配置
├── eslint.config.mjs       # ESLint 配置
└── tsconfig.json           # TypeScript 配置
```

## 许可证

MIT