---
title: "框选"
description: "框选"
language: "zh"
canonical: "https://x6.antv.antgroup.com/zh/tutorial/plugins/selection/"
version: "3.x"
---

[资料索引](/llms.txt)

> **在本章节中主要介绍框选插件相关的知识，通过阅读，你可以了解到**

- 如何启用选择与框选
- 如何配置多选与严格框选
- 如何设置修饰键与触发事件（eventTypes）


## 使用

你可以通过插件 `Selection` 启用选择与框选功能，示例：

```ts
import { Graph, Selection } from '@antv/x6'

const graph = new Graph({
  background: {
    color: '#F2F7FA',
  },
})
graph.use(
  new Selection({
    enabled: true,
  }),
)
```

## 演示

- 点击选中节点。
- 启用多选，按住 Ctrl/Command 后点击节点多选。
- 启用移动，拖动选框移动节点。
- 启用框选，在画布空白位置按下鼠标左键，拖动选框来框选节点。
- 启用严格框选（strict）模式，观察其对框选的影响。
- 选择与框选配合使用的修饰键，如 `alt`；按住 `alt` 键，在画布空白处按下鼠标左键并拖动选框来框选节点。
- 应用自定义过滤器（排除 circle 节点），圆形节点不能被选中。
- 应用自定义附加内容（显示选中节点个数），选择两个及以上的节点，触发显示自定义内容。



```ts
import './index.less'
import { createRoot } from 'react-dom/client'
import React from 'react'
import { Graph, Selection } from '@antv/x6'
import { Settings, State } from './settings.tsx'

export default class Example extends React.Component {
  private container: HTMLDivElement
  private graph: Graph

  componentDidMount() {
    this.graph = new Graph({
      container: this.container,
      background: {
        color: '#F2F7FA',
      },
    })

    this.graph.use(
      new Selection({
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
        showNodeSelectionBox: true,
      }),
    )

    this.graph.addNode({
      x: 320,
      y: 100,
      width: 100,
      height: 40,
      label: 'Rect',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    const source = this.graph.addNode({
      x: 80,
      y: 50,
      width: 100,
      height: 40,
      label: 'Hello',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
      },
    })

    const target = this.graph.addNode({
      shape: 'circle',
      x: 240,
      y: 200,
      width: 60,
      height: 60,
      label: 'World',
      attrs: {
        body: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
          fill: '#fff',
        },
      },
    })

    this.graph.addEdge({
      source,
      target,
      attrs: {
        line: {
          stroke: '#8f8f8f',
          strokeWidth: 1,
        },
      },
    })
  }

  onSettingChanged = (options: State) => {
    this.graph.toggleMultipleSelection(options.multiple)
    this.graph.toggleSelectionMovable(options.movable)
    this.graph.toggleRubberband(options.rubberband)
    this.graph.toggleStrictRubberband(options.strict)
    this.graph.setSelectionFilter(options.filter)
    this.graph.setRubberbandModifiers(options.modifiers as any)
    this.graph.setSelectionDisplayContent(
      options.content
        ? (selection) => {
            return `${selection.length} node${
              selection.length > 1 ? 's' : ''
            } selected.`
          }
        : null,
    )
  }

  refContainer = (container: HTMLDivElement) => {
    this.container = container
  }

  render() {
    return (
      <div className="selection-app">
        <div className="app-side">
          <Settings onChange={this.onSettingChanged} />
        </div>
        <div className="app-content" ref={this.refContainer} />
      </div>
    )
  }
}

const root = createRoot(document.getElementById('container')!)
root.render(<Example />)
window.addEventListener('pagehide', () => root.unmount(), { once: true })
```



## 配置

| 属性名                     | 类型                 | 默认值                                | 必选 | 描述                                                                                                                                           |
| -------------------------- | -------------------- | ------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| enabled                    | boolean              | `true`                                |      | 是否启用 Selection 插件                                                                                                                        |
| className                  | string               | -                                     |      | 附加样式名，用于定制样式                                                                                                                       |
| multiple                   | boolean              | `true`                                |      | 是否启用点击多选，启用后按住 `ctrl` 或 `command` 键点击节点实现多选                                                                            |
| multipleSelectionModifiers | ModifierKey          | `['ctrl', 'meta']`                    |      | 用于设置上面点击多选配套的修饰键                                                                                                               |
| rubberband                 | boolean              | `false`                               |      | 是否启用框选节点功能                                                                                                                           |
| rubberNode                 | boolean              | `true`                                |      | 框选时是否将节点纳入框选范围计算                                                                                                               |
| rubberEdge                 | boolean              | `false`                               |      | 框选时是否将边纳入框选范围计算                                                                                                                 |
| modifiers                  | ModifierKey          | -                                     |      | 用于设置上面框选配套的修饰键                                                                                                                   |
| strict                     | boolean              | `false`                               |      | 选框是否需要完全包围节点时才选中节点                                                                                                           |
| movable                    | boolean              | `true`                                |      | 拖动选框时框选的节点是否一起移动                                                                                                               |
| content                    | string               | -                                     |      | 设置附加显示的内容                                                                                                                             |
| filter                     | Filter               | -                                     |      | 节点过滤器                                                                                                                                     |
| showNodeSelectionBox       | boolean              | `false`                               |      | 是否显示节点的选择框                                                                                                                           |
| showEdgeSelectionBox       | boolean              | `false`                               |      | 是否显示边的选择框                                                                                                                             |
| pointerEvents              | `'none' \| 'auto'`   | `auto`                                |      | 如果打开 `showNodeSelectionBox` 时，会在节点上方盖一层元素，导致节点的事件无法响应，此时可以配置 `pointerEvents: none` 来解决，默认值是 `auto` |
| eventTypes                 | SelectionEventType[] | `['leftMouseDown', 'mouseWheelDown']` |      | 用于设置框选的触发事件类型                                                                                                                     |
| movingRouterFallback       | string               | -                                     |      | 批量拖拽框选节点过程中，支持临时将与选中节点相连边的路由降级为指定路由，拖拽停止并空闲后自动恢复为原始路由（推荐在拖拽大量节点且边的原始路由为 `manhattan` 时，将 `movingRouterFallback` 设置为 `orth`，能有效提升拖拽流畅性） |

`Filter` 的类型定义如下：

```ts
type Filter = string[] | { id: string }[] | (this: Graph, cell: Cell) => boolean
```

- `string[]`： 节点 shape 数组，指定的节点/边 shape 才能被选中
- `({ id: string })[]`： 节点 ID 数组，指定的节点/边才能被选中
- `(this: Graph, cell: Cell) => boolean`： 返回 true 的节点/边才能被选中

`ModifierKey` 的类型定义如下：

```ts
type ModifierKey = string | ('alt' | 'ctrl' | 'meta' | 'shift' | 'space')[] | null
```

X6 中修饰键包括 `alt`、`ctrl`、`meta`、`shift`、`space` 五个，设置修饰键后点击鼠标并按下修饰键即可触发相应的行为。如果框选和画布拖拽平移的触发条件完全相同时，即相同事件类型（eventTypes）和修饰键（modifiers），框选的优先级更高（禁用默认的画布拖拽平移）；如果触发条件不同，则互不影响。因此在同时开始框选和拖拽画布时，修饰键就非常有用，比如框选和拖拽画布的触发时机都是鼠标左键在画布空白位置按下（leftMouseDown），这时可以为框选和拖拽画布设置不一样的修饰键，达到同时开启又不冲突的效果。支持配置单个（如 `alt`）或多个（如 `['alt', 'ctrl']`）修饰键，通过数组形式配置的多个修饰键是或关系，比如刚刚配置的修饰键表示按下 `alt` 或 `ctrl`，如果需要更加灵活的配置，可以使用如下这些形式：

- `alt` 表示按下 `alt`。
- `[alt, ctrl]`, 表示按下 `alt` 或 `ctrl`。
- `alt|ctrl` 表示按下 `alt` 或 `ctrl`。
- `alt&ctrl` 表示同时按下 `alt` 和 `ctrl`。
- `alt|ctrl&shift` 表示同时按下 `alt` 和 `shift` 或者同时按下 `ctrl` 和 `shift`。

`SelectionEventType` 的类型定义如下：

```ts
type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown';
```

触发框选的交互方式。支持2种形式或者他们之间的组合：

- `leftMouseDown`: 按下鼠标左键移动进行拖拽
- `mouseWheelDown`: 按下鼠标滚轮进行拖拽

## API

### graph.select(...)

```ts
select(cells: Cell | string | (Cell | string)[]): this
```

选中指定的节点/边。需要注意的是，该方法不会取消选中当前选中的节点/边，而是将指定的节点/边追加到选区中。如果同时需要取消选中当前选中的节点/边，请使用 [resetSelection(...)](#graphresetselection) 方法。

### graph.unselect(...)

```ts
unselect(cells: Cell | string | (Cell | string)[]): this
```

取消选中指定的节点/边。

### graph.isSelected(...)

```ts
isSelected(cell: Cell | string): boolean
```

返回指定的节点/边是否被选中。

### graph.resetSelection(...)

```ts
resetSelection(cells?: Cell | string | (Cell | string)[]): this
```

先清空选区，然后选中提供的节点/边。

### graph.getSelectedCells()

```ts
getSelectedCells(): Cell[]
```

获取选中的节点/边。

### graph.cleanSelection()

```ts
cleanSelection(): this
```

清空选区。

### graph.isSelectionEmpty()

```ts
isSelectionEmpty(): boolean
```

返回选区是否为空。

### graph.isSelectionEnabled()

```ts
isSelectionEnabled(): boolean
```

返回是否启用选择能力。

### graph.enableSelection()

```ts
enableSelection(): this
```

启用选择能力。

### graph.disableSelection()

```ts
disableSelection(): this
```

禁用选择能力。

### graph.toggleSelection(...)

```ts
toggleSelection(enabled?: boolean): this
```

切换选择的启用状态。参数如下：

| 名称    | 类型    | 必选 | 默认值 | 描述                                       |
|---------|---------|:----:|--------|------------------------------------------|
| enabled | boolean |      | -      | 是否启用选择能力，缺省时切换选择的启用状态。 |

### graph.isMultipleSelection()

```ts
isMultipleSelection(): boolean
```

返回是否启用了多选。

### graph.enableMultipleSelection()

```ts
enableMultipleSelection(): this
```

启用多选。

### graph.disableMultipleSelection()

```ts
disableMultipleSelection(): this
```

禁用多选。

### graph.toggleMultipleSelection(...)

```ts
toggleMultipleSelection(multiple?: boolean): this
```

切换多选的启用状态。参数如下：

| 名称     | 类型    | 必选 | 默认值 | 描述                                   |
|----------|---------|:----:|--------|--------------------------------------|
| multiple | boolean |      | -      | 是否启用多选，缺省时切换多选的启用状态。 |

### graph.isSelectionMovable()

```ts
isSelectionMovable(): boolean
```

返回选中的节点/边是否可以被移动。

### graph.enableSelectionMovable()

```ts
enableSelectionMovable(): this
```

启用选中的节点/边的移动。

### graph.disableSelectionMovable()

```ts
disableSelectionMovable(): this
```

禁用选中节点/边的移动。

### graph.toggleSelectionMovable(...)

```ts
toggleSelectionMovable(enabled?: boolean): this
```

切换选中节点/边是否可以被移动。参数如下：

| 名称    | 类型    | 必选 | 默认值 | 描述                                            |
|---------|---------|:----:|--------|-----------------------------------------------|
| enabled | boolean |      | -      | 是否启用选中的节点/边的移动，缺省时切换启用状态。 |

### graph.isRubberbandEnabled()

```ts
isRubberbandEnabled(): boolean
```

返回是否启用了框选。

### graph.enableRubberband()

```ts
enableRubberband(): this
```

启用框选。

### graph.disableRubberband()

```ts
disableRubberband(): this
```

禁用框选。

### graph.toggleRubberband(...)

```ts
toggleRubberband(enabled?: boolean): this
```

切换框选的启用状态。参数如下：

| 名称    | 类型    | 必选 | 默认值 | 描述                             |
|---------|---------|:----:|--------|--------------------------------|
| enabled | boolean |      | -      | 是否启用框选，缺省时切换启用状态。 |

### graph.isStrictRubberband()

```ts
isStrictRubberband(): boolean
```

返回是否启用了严格框选。启用严格框选后，只有节点/边被选框完全包围时才会选中节点/边。

### graph.enableStrictRubberband()

```ts
enableStrictRubberband(): this
```

启用严格框选。启用严格框选后，只有节点/边被选框完全包围时才会选中节点/边。

### graph.disableStrictRubberband()

```ts
disableStrictRubberband(): this
```

禁用严格框选。禁用严格框选后，只需要选框与节点/边的包围盒相交即可选中节点/边。

### graph.toggleStrictRubberband(...)

```ts
toggleStrictRubberband(enabled?: boolean): this
```

切换严格框选的启用状态。参数如下：

| 名称    | 类型    | 必选 | 默认值 | 描述                                 |
|---------|---------|:----:|--------|------------------------------------|
| enabled | boolean |      | -      | 是否启用严格框选，缺省时切换启用状态。 |

### graph.setSelectionFilter(...)

```ts
setSelectionFilter(
  filter?:
   | null
   | (string | { id: string })[]
   | ((this: Graph, cell: Cell) => boolean)
): this
```

设置选择的过滤条件，满足过滤条件的节点/边才能被选中。

开启 `filter` 后，blank 上 rubberband 框选过程中 `box:mousemove` 和 `box:mouseup` 事件返回的 `nodes`、`edges` 也会应用相同的过滤规则，因此其预览结果会和最终 selection 保持一致。

### graph.setRubberbandModifiers(...)

```ts
setRubberbandModifiers(modifiers?: string | ModifierKey[] | null): this
```

设置框选的修饰键，只有同时按下修饰键时才能触发框选。

### graph.setSelectionDisplayContent(...)

```ts
setSelectionDisplayContent(
  content?:
   | null
   | false
   | string
   | ((this: Graph, selection: Selection, contentElement: HTMLElement) => string)
): this
```

设置选中节点/边的附加显示内容。

## 事件

| 事件名称            | 参数类型                                                                        | 描述                              |
|---------------------|---------------------------------------------------------------------------------|---------------------------------|
| `cell:selected`     | `{ cell: Cell; options: Model.SetOptions }`                                     | 节点/边被选中时触发               |
| `node:selected`     | `{ node: Node; options: Model.SetOptions }`                                     | 节点被选中时触发                  |
| `edge:selected`     | `{ edge: Edge; options: Model.SetOptions }`                                     | 边被选中时触发                    |
| `cell:unselected`   | `{ cell: Cell; options: Model.SetOptions }`                                     | 节点/边被取消选中时触发           |
| `node:unselected`   | `{ node: Node; options: Model.SetOptions }`                                     | 节点被取消选中时触发              |
| `edge:unselected`   | `{ edge: Edge; options: Model.SetOptions }`                                     | 边被取消选中时触发                |
| `box:mousedown`     | `{ e: Dom.MouseDownEvent; view: CellView \| null; cell: Cell \| null; x: number; y: number; nodes: Node[]; edges: Edge[] }` | 按下 selection box，或在画布空白处开始 rubberband 框选时触发 |
| `box:mousemove`     | `{ e: Dom.MouseMoveEvent; view: CellView \| null; cell: Cell \| null; x: number; y: number; nodes: Node[]; edges: Edge[] }` | 拖动 selection box，或 rubberband 框选过程中实时触发 |
| `box:mouseup`       | `{ e: Dom.MouseUpEvent; view: CellView \| null; cell: Cell \| null; x: number; y: number; nodes: Node[]; edges: Edge[] }` | 结束拖动 selection box，或结束 rubberband 框选时触发 |
| `selection:changed` | `{added: Cell[]; removed: Cell[]; selected: Cell[]; options: Model.SetOptions}` | 选中的节点/边发生改变(增删)时触发 |

`box:*` 事件中的参数说明：

- `x`、`y`：当前鼠标所在的图坐标。
- `nodes`、`edges`：当前 box 对应的节点和边集合。
- `view`、`cell`：当前关联的视图和单元，在 blank 上进行 rubberband 框选时可能为 `null`。

`nodes` 和 `edges` 在不同交互阶段表示的含义如下：

- 在画布空白处开始或拖动 rubberband 框选时，`nodes` 和 `edges` 表示当前选框实时命中的节点和边； `strict` 和 `filter` 配置会影响该结果。
- 在拖动已有 selection box 时，`nodes` 和 `edges` 表示当前 selection 中的节点和边。

```ts
graph.on('node:selected', ({ node }) => {
  console.log(node)
})

graph.on('box:mousemove', ({ nodes, edges, cell }) => {
  console.log(nodes, edges, cell)
})

// 我们也可以在插件实例上监听事件
selection.on('node:selected', ({ node }) => {
  console.log(node)
})
```
### docs/demos/tutorial/plugins/selection/index.less

```less
.selection-app {
  display: flex;
  border: 1px solid #f0f0f0;
  padding: 16px 8px;
  font-family: sans-serif;

  .app-side {
    bottom: 0;
    padding: 0 8px;
  }

  .app-content {
    flex: 1;
    margin-right: 8px;
    margin-left: 8px;
    box-shadow: 0 0 10px 1px #e9e9e9;
  }

  .ant-card {
    box-shadow: 0 0 10px 1px #e9e9e9;
  }

  .ant-card-head-title {
    text-align: center;
  }

  .ant-row {
    margin: 16px 0;
    text-align: left;
  }

  .x6-widget-selection-box {
    border: 2px dashed #239edd;
  }

  .x6-widget-selection-inner {
    border: 1px solid #239edd;
  }
}
```
### docs/demos/tutorial/plugins/selection/settings.tsx

```tsx
import React from 'react'
import { Checkbox, Switch, Card, Row, Col } from 'antd'
import type { CheckboxChangeEvent } from 'antd/es/checkbox'

export interface Props {
  onChange: (res: State) => void
}

export interface State {
  multiple: boolean
  rubberband: boolean
  strict: boolean
  movable: boolean
  modifiers: string[]
  filter?: string[]
  content: boolean
}

export class Settings extends React.Component<Props, State> {
  state: State = {
    multiple: true,
    rubberband: true,
    movable: true,
    strict: false,
    modifiers: [],
    content: false,
  }

  notifyChange() {
    this.props.onChange({
      ...this.state,
    })
  }

  onMultipleChanged = (multiple: boolean) => {
    this.setState({ multiple }, () => {
      this.notifyChange()
    })
  }

  onMovableChanged = (movable: boolean) => {
    this.setState({ movable }, () => {
      this.notifyChange()
    })
  }

  onRubberbandChanged = (rubberband: boolean) => {
    this.setState({ rubberband }, () => {
      this.notifyChange()
    })
  }

  onStrictChanged = (strict: boolean) => {
    this.setState({ strict }, () => {
      this.notifyChange()
    })
  }

  onModifiersChange = (modifiers: string[]) => {
    this.setState({ modifiers }, () => {
      this.notifyChange()
    })
  }

  onFilterChanged = (e: CheckboxChangeEvent) => {
    this.setState(
      {
        filter: e.target.checked ? ['circle'] : undefined,
      },
      () => {
        this.notifyChange()
      },
    )
  }

  onContentChanged = (e: CheckboxChangeEvent) => {
    this.setState({ content: e.target.checked }, () => {
      this.notifyChange()
    })
  }

  render() {
    return (
      <Card
        title="Selection Settings"
        size="small"
        bordered={false}
        style={{ width: 320 }}
      >
        <Row align="middle">
          <Col span={14}>Enable Multiple Select</Col>
          <Col span={10}>
            <Switch
              checked={this.state.multiple}
              onChange={this.onMultipleChanged}
            />
          </Col>
        </Row>
        <Row align="middle">
          <Col span={14}>Selection Movable</Col>
          <Col span={10}>
            <Switch
              checked={this.state.movable}
              onChange={this.onMovableChanged}
            />
          </Col>
        </Row>
        <Row
          align="middle"
          style={{
            margin: '0 -12px',
          }}
        >
          <Col span={24} style={{ borderBottom: '1px solid #e9e9e9' }} />
        </Row>
        <Row align="middle">
          <Col span={14}>Enable Rubberband</Col>
          <Col span={10}>
            <Switch
              checked={this.state.rubberband}
              onChange={this.onRubberbandChanged}
            />
          </Col>
        </Row>
        <Row align="middle">
          <Col span={14}>Is Strict Contains</Col>
          <Col span={10}>
            <Switch
              checked={this.state.strict}
              onChange={this.onStrictChanged}
            />
          </Col>
        </Row>
        <Row align="middle">
          <Col span={8}>Modifier Key</Col>
          <Col span={16}>
            <Checkbox.Group
              options={['alt', 'ctrl', 'shift']}
              value={this.state.modifiers}
              onChange={this.onModifiersChange}
            />
          </Col>
        </Row>
        <Row
          align="middle"
          style={{
            margin: '0 -12px',
          }}
        >
          <Col span={24} style={{ borderBottom: '1px solid #e9e9e9' }} />
        </Row>
        <Row align="middle">
          <Col span={24}>
            <Checkbox
              checked={this.state.filter != null}
              onChange={this.onFilterChanged}
            >
              Add filter (only circle)
            </Checkbox>
          </Col>
        </Row>
        <Row align="middle">
          <Col span={24}>
            <Checkbox
              checked={this.state.content}
              onChange={this.onContentChanged}
            >
              Add content(display selected count)
            </Checkbox>
          </Col>
        </Row>
      </Card>
    )
  }
}
```
