---
title: "useSigmaDrag"
description: "把 sigma 的 enableNodeDrag 接进 Vue 的响应式，开关跟随 enabled，过程暴露为 dragged 与 isDragging。"
canonical_url: "https://sigma.mhaibaraai.cn/docs/composables/use-sigma-drag"
---
# useSigmaDrag

> 把 sigma 的 enableNodeDrag 接进 Vue 的响应式，开关跟随 enabled，过程暴露为 dragged 与 isDragging。

## 用法

拖拽本身由 sigma v4 内建的 `enableNodeDrag` 实现，本 composable 不重复造：它只负责把开关接上 Vue 的响应式，并把 `nodeDragStart` / `nodeDragEnd` 事件镜像成 ref。调用一次即可，无需接线：

```vue [UseSigmaDragExample.vue]
<script setup lang="ts">
defineProps<{ enabled: boolean }>()

const { data } = await useFetch('/api/small.json')
</script>

<template>
  <SigmaGraph :data="data" :settings="{ itemSizesReference: 'screen' }">
    <UseSigmaDragPanel :enabled="enabled" />
  </SigmaGraph>
</template>
```

```vue [UseSigmaDragPanel.vue]
<script setup lang="ts">
const { dragged, isDragging } = useSigmaDrag()
</script>
```

### `enabled`

接受 ref、getter 或裸值，变了立刻生效，不必等下一次按下。实际落到 sigma 的 `enableNodeDrag` 设置上：

```ts
const editable = shallowRef(false)
useSigmaDrag({ enabled: editable })
```

### `onStart` / `onEnd`

拖拽起止的回调，第二个参数是本次实际会移动的全部节点。典型用途是拖完把坐标存回服务端：

```ts
const { graph } = useSigma()

useSigmaDrag({
  onEnd: (node) => {
    $fetch(`/api/graph/nodes/${node}/position`, {
      method: 'PATCH',
      body: { x: graph.value.getNodeAttribute(node, 'x'), y: graph.value.getNodeAttribute(node, 'y') }
    })
  }
})
```

## 示例

### 拖拽中的外观

被拖拽的节点自带 `isDragged` 状态，改外观走 styles，不必往图数据里写临时属性：

```vue
<SigmaGraph
  :data="data"
  :styles="{
    nodes: [
      { color: { attribute: 'color' }, size: { attribute: 'size' } },
      { whenState: 'isDragged', then: { color: '#f59e0b', labelVisibility: 'visible' } }
    ]
  }"
/>
```

### 一次拖多个节点

传 `settings.getDraggedNodes` 返回哪些节点要跟着一起动，`onStart` / `onEnd` 的第二个参数与 `draggedNodes` 拿到的就是它的返回值：

```ts
// 拖一个节点，它的一度邻居跟着走
const settings = {
  getDraggedNodes: (node: string) => [node, ...graph.neighbors(node)]
}
```

写回的属性名默认是 `x` / `y`，要写到别的字段上用 `settings.dragPositionToAttributes`，签名是 `(position: Coordinates, node: string) => Record<string, unknown>`。

### 与迭代型布局互斥

> [!WARNING]
> 
> ForceAtlas2、Noverlap 这类布局在跑的时候会**持续回写坐标**，拖拽结果被立刻覆盖，表现为节点怎么拖都弹回去。需要手动摆位时先停掉布局：
> 
> ```ts
> const layout = useSigmaLayout('forceatlas2')
> useSigmaDrag({ onStart: () => layout.stop() })
> ```

一次性布局（`circular`、`circlepack`、`random`，以及 `assign()` 调用）没有这个问题，跑完就结束了。示例传了 `itemSizesReference: 'screen'`，规避布局改动坐标跨度后节点成倍胀大。

## API

### useSigmaDrag()

`useSigmaDrag(options?: UseSigmaDragOptions): UseSigmaDragReturn`

#### Options

**enabled** (`MaybeRefOrGetter<boolean>`): 默认 true —— 是否启用拖拽。响应式，实际落到 sigma 的 enableNodeDrag 设置上。

**onStart** (`(node: string, allDraggedNodes: string[]) => void`): 拖拽开始时触发。第二个参数是本次实际会移动的全部节点，由 settings.getDraggedNodes 决定。

**onEnd** (`(node: string, allDraggedNodes: string[]) => void`): 拖拽结束时触发。

#### Returns

**dragged** (`Readonly<Ref<string | null>>`): 正在拖拽的节点，未拖拽时为 null。

**draggedNodes** (`Readonly<Ref<string[]>>`): 本次拖拽实际移动的全部节点，未拖拽时为空数组。

**isDragging** (`ComputedRef<boolean>`): 是否正在拖拽。

类型从根出口取：

```ts
import type { UseSigmaDragOptions, UseSigmaDragReturn } from '@movk/sigma'
```


## Sitemap

See the full [sitemap](https://sigma.mhaibaraai.cn/sitemap.md) for all pages.
