Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions sites/docs/docs/tutorial/basic/edge.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,165 @@ The effect is as follows:

<code id="edge-shapes" src="../../../src/tutorial/basic/edge/shapes"></code>

## Three Edge Rendering Forms

### Line

Line is the simplest edge type. It renders directly using an SVG `<line>` element connecting the start point to the end point.

**Rendering characteristics**:

- Uses an SVG `<line>` element where `x1/y1` is the start point and `x2/y2` is the end point.
- Simplest path calculation: only `startPoint` and `endPoint` coordinates are needed.
- Click area (AppendWidth): a rectangle is computed on both sides of the line so that thin lines are easier to click.

```tsx | pure
// LineEdge getEdge core rendering
getEdge() {
const { model } = this.props
const { startPoint, endPoint } = model
return (
<Line
x1={startPoint.x}
y1={startPoint.y}
x2={endPoint.x}
y2={endPoint.y}
/>
)
}
```

### Polyline

Polyline (orthogonal polyline) is a multi-segment line where every segment is either horizontal or vertical. It is rendered using an SVG `<polyline>` element.

**Rendering characteristics**:

- Uses an SVG `<polyline>` element with all waypoints passed in the `points` attribute (format: `"x1,y1 x2,y2 x3,y3 ..."`).
- Complex path calculation: uses an A* algorithm with Manhattan distance to automatically route around nodes; results are stored in `pointsList`.
- Click area (AppendWidth): each segment has its own rectangular hit region that are all combined together.

```tsx | pure
// PolylineEdge getEdge core rendering
getEdge() {
const { model } = this.props
const { points } = model // "x1,y1 x2,y2 x3,y3 ..."
return (
<Polyline
points={points}
/>
)
}
```

### Bezier

The bezier edge is a cubic Bézier curve rendered using an SVG `<path>` element with the `M...C...` command.

**Rendering characteristics**:

- Uses an SVG `<path>` element. The path format is `M startX startY C sNextX sNextY, ePreX ePreY, endX endY`.
- `pointsList` always contains exactly 4 points: **start**, **start control point (sNext)**, **end control point (ePre)**, **end**.
- The initial positions of the two control points are calculated automatically based on the source and target node positions so the curve avoids overlapping node borders.
- Click area (AppendWidth): a transparent curve with `strokeWidth=10` is drawn on top of the actual path to enlarge the hit area.

```tsx | pure
// BezierEdgeModel path generation
private getPath(points: Point[]): string {
const [start, sNext, ePre, end] = points
return `M ${start.x} ${start.y}
C ${sNext.x} ${sNext.y},
${ePre.x} ${ePre.y},
${end.x} ${end.y}`
}
```

## Operation Point Differences

"Operation points" are the interactive handles shown when an edge is selected, used to adjust its shape. All three edge types support common start/end adjustment points, but each type also has its own unique handles.

### Common: Start/End Adjustment Points

All three edge types support start/end adjustment points. Enable them at initialization with `adjustEdgeStartAndEnd`:

```tsx | pure
const lf = new LogicFlow({
adjustEdgeStartAndEnd: true, // Enable start/end point adjustment
})
```

When enabled, a circular handle appears at both the **start** and **end** of a selected edge. Drag either handle to reconnect the edge to a different anchor on another node.

### Line Operation Points

A line has **only** start/end adjustment points. There is no way to change the intermediate path because a straight line between two points is unique.

| Operation Point | Description |
|----------------|-------------|
| Start adjustment (SOURCE) | Drag to reconnect to a different node anchor |
| End adjustment (TARGET) | Drag to reconnect to a different node anchor |

### Polyline Operation Points

In addition to start/end adjustment points, a polyline also supports **segment dragging**. Each segment has a transparent draggable region (generated by `getAppendWidth`):

- **Horizontal segments**: can only be dragged vertically (move the segment up/down); cursor becomes `ns-resize`.
- **Vertical segments**: can only be dragged horizontally (move the segment left/right); cursor becomes `ew-resize`.

Use `adjustEdgeMiddle` to restrict dragging to middle segments only, preventing the first and last segments (which connect to nodes) from being accidentally moved:

```tsx | pure
const lf = new LogicFlow({
adjustEdgeStartAndEnd: true,
adjustEdgeMiddle: true, // Only middle segments can be dragged
})
```

| Operation Point | Description |
|----------------|-------------|
| Start adjustment (SOURCE) | Drag to reconnect to a different node anchor |
| End adjustment (TARGET) | Drag to reconnect to a different node anchor |
| Segment drag regions | Translate the segment horizontally or vertically |

### Bezier Operation Points

In addition to start/end adjustment points, two **Bézier control points** (`sNext` and `ePre`) and their guide lines appear when a bezier edge is selected (rendered by `BezierAdjustOverlay`):

- **sNext** (start control point): connected to the start point by a guide line; drag it to change the curvature direction and magnitude near the start.
- **ePre** (end control point): connected to the end point by a guide line; drag it to change the curvature direction and magnitude near the end.
- The two control points are independent of each other.

```tsx | pure
// BezierAdjustOverlay control-point rendering logic
getBezierAdjust(bezier: BezierEdgeModel, graphModel: GraphModel) {
const [start, sNext, ePre, end] = getBezierPoints(bezier.path)
return [
// Start side: guide line + sNext control point
<Line x1={start.x} y1={start.y} x2={sNext.x} y2={sNext.y} />,
<BezierAdjustAnchor position={sNext} type="sNext" />,
// End side: guide line + ePre control point
<Line x1={end.x} y1={end.y} x2={ePre.x} y2={ePre.y} />,
<BezierAdjustAnchor position={ePre} type="ePre" />,
]
}
```

| Operation Point | Description |
|----------------|-------------|
| Start adjustment (SOURCE) | Drag to reconnect to a different node anchor |
| End adjustment (TARGET) | Drag to reconnect to a different node anchor |
| sNext (start control point) | Drag to change curve shape near the start |
| ePre (end control point) | Drag to change curve shape near the end |

### Operation Point Comparison

| Operation Point Type | Line | Polyline | Bezier |
|---------------------|:----:|:--------:|:------:|
| Start adjustment (SOURCE) | ✓ | ✓ | ✓ |
| End adjustment (TARGET) | ✓ | ✓ | ✓ |
| Segment drag (move segments individually) | ✗ | ✓ | ✗ |
| Bézier control points (sNext / ePre) | ✗ | ✗ | ✓ |

## Selecting built-in edges inherited by custom edges

```tsx | pure
Expand Down
159 changes: 159 additions & 0 deletions sites/docs/docs/tutorial/basic/edge.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,165 @@ toc: content

<code id="edge-shapes" src="../../../src/tutorial/basic/edge/shapes"></code>

## 三种边的渲染形式

### 直线(line)

直线是最简单的边类型,通过 SVG 的 `<line>` 标签直接连接起点与终点,路径唯一确定。

**渲染特点**:

- 底层使用 SVG `<line>` 元素,`x1/y1` 为起点,`x2/y2` 为终点。
- 路径计算最简:只需 `startPoint` 和 `endPoint` 两个坐标。
- 选中区域(AppendWidth):以直线为中轴,向两侧各扩展一定宽度,形成矩形点击区,方便用户选中细线。

```tsx | pure
// LineEdge 的 getEdge 核心渲染
getEdge() {
const { model } = this.props
const { startPoint, endPoint } = model
return (
<Line
x1={startPoint.x}
y1={startPoint.y}
x2={endPoint.x}
y2={endPoint.y}
/>
)
}
```

### 折线(polyline)

折线(直角折线)是所有线段均为水平或垂直方向的多段线,通过 SVG 的 `<polyline>` 标签渲染多个折点。

**渲染特点**:

- 底层使用 SVG `<polyline>` 元素,通过 `points` 属性传入所有折点坐标(格式:`"x1,y1 x2,y2 x3,y3 ..."`)。
- 路径计算复杂:采用 A* 算法结合曼哈顿距离,自动绕过节点计算最优正交路径,结果存储在 `pointsList` 中。
- 选中区域(AppendWidth):将折线拆分为每段线段,对每段单独计算矩形扩展区域并叠加。

```tsx | pure
// PolylineEdge 的 getEdge 核心渲染
getEdge() {
const { model } = this.props
const { points } = model // "x1,y1 x2,y2 x3,y3 ..."
return (
<Polyline
points={points}
/>
)
}
```

### 贝塞尔曲线(bezier)

贝塞尔曲线是三次贝塞尔曲线,通过 SVG `<path>` 的 `M...C...` 命令绘制光滑曲线。

**渲染特点**:

- 底层使用 SVG `<path>` 元素,路径格式为 `M startX startY C sNextX sNextY, ePreX ePreY, endX endY`。
- `pointsList` 固定包含 4 个点:**起点**、**起点控制点(sNext)**、**终点控制点(ePre)**、**终点**。
- 控制点的初始位置根据起终点所在节点的方位自动计算,使曲线尽量不与节点边框重叠。
- 选中区域(AppendWidth):在相同路径上绘制一条宽度为 10、颜色透明的曲线,扩大点击范围。

```tsx | pure
// BezierEdgeModel 的路径生成
private getPath(points: Point[]): string {
const [start, sNext, ePre, end] = points
return `M ${start.x} ${start.y}
C ${sNext.x} ${sNext.y},
${ePre.x} ${ePre.y},
${end.x} ${end.y}`
}
```

## 三种边的操作点区别

"操作点"是指边被选中后,用于调整边形态的交互控件。三种边均支持公共的起终点调整点,但各自还有独特的操作点。

### 公共操作:起终点调整点

三种边都支持起终点调整点,需在初始化时开启 `adjustEdgeStartAndEnd`:

```tsx | pure
const lf = new LogicFlow({
adjustEdgeStartAndEnd: true, // 开启起终点调整功能
})
```

开启后,选中边时在**起点**和**终点**各显示一个圆形调整点,拖拽可将边重新连接到其他节点的锚点。

### 直线(line)的操作点

直线**仅有**起终点调整点,无法改变中间路径——因为两点之间直线唯一,没有可调整的中间段。

| 操作点 | 说明 |
|--------|------|
| 起点调整点(SOURCE) | 拖拽重新连接到其他节点锚点 |
| 终点调整点(TARGET) | 拖拽重新连接到其他节点锚点 |

### 折线(polyline)的操作点

折线除起终点调整点外,还支持**线段拖拽**。每个线段均有透明可拖拽区域(由 `getAppendWidth` 生成):

- **水平线段**:只能沿垂直方向拖拽(纵向平移该段);光标变为 `ns-resize`。
- **垂直线段**:只能沿水平方向拖拽(横向平移该段);光标变为 `ew-resize`。

通过配置 `adjustEdgeMiddle` 可进一步限制只允许拖拽中间线段,防止连接节点的首尾段被意外移动:

```tsx | pure
const lf = new LogicFlow({
adjustEdgeStartAndEnd: true,
adjustEdgeMiddle: true, // 仅允许拖拽中间线段,首尾线段不可拖拽
})
```

| 操作点 | 说明 |
|--------|------|
| 起点调整点(SOURCE) | 拖拽重新连接到其他节点锚点 |
| 终点调整点(TARGET) | 拖拽重新连接到其他节点锚点 |
| 各线段拖拽区域 | 沿水平或垂直方向平移对应线段 |

### 贝塞尔曲线(bezier)的操作点

贝塞尔曲线除起终点调整点外,选中时还会显示**两个贝塞尔控制点**(`sNext` 和 `ePre`)及其辅助连线(由 `BezierAdjustOverlay` 渲染):

- **sNext**(起点控制点):通过辅助线与起点相连,拖拽可改变曲线起点侧的弯曲方向和幅度。
- **ePre**(终点控制点):通过辅助线与终点相连,拖拽可改变曲线终点侧的弯曲方向和幅度。
- 两个控制点相互独立,可以单独调节。

```tsx | pure
// BezierAdjustOverlay 中的控制点渲染逻辑
getBezierAdjust(bezier: BezierEdgeModel, graphModel: GraphModel) {
const [start, sNext, ePre, end] = getBezierPoints(bezier.path)
return [
// 起点侧:辅助线 + sNext 控制点
<Line x1={start.x} y1={start.y} x2={sNext.x} y2={sNext.y} />,
<BezierAdjustAnchor position={sNext} type="sNext" />,
// 终点侧:辅助线 + ePre 控制点
<Line x1={end.x} y1={end.y} x2={ePre.x} y2={ePre.y} />,
<BezierAdjustAnchor position={ePre} type="ePre" />,
]
}
```

| 操作点 | 说明 |
|--------|------|
| 起点调整点(SOURCE) | 拖拽重新连接到其他节点锚点 |
| 终点调整点(TARGET) | 拖拽重新连接到其他节点锚点 |
| sNext(起点控制点) | 拖拽改变曲线起点侧的弯曲形态 |
| ePre(终点控制点) | 拖拽改变曲线终点侧的弯曲形态 |

### 操作点对比

| 操作点类型 | 直线 | 折线 | 贝塞尔曲线 |
|-----------|:----:|:----:|:----------:|
| 起点调整(SOURCE) | ✓ | ✓ | ✓ |
| 终点调整(TARGET) | ✓ | ✓ | ✓ |
| 线段拖拽(逐段移动) | ✗ | ✓ | ✗ |
| 贝塞尔控制点(sNext / ePre) | ✗ | ✗ | ✓ |

## 选择自定义边继承的内置边

```tsx | pure
Expand Down