Skip to content

Drag Plugin(拖拽交互)

包名rendx-drag-plugin · 包参考

为节点提供拖拽移动能力。独立运行于纯 engine 场景,也可与 graph-plugin、selection-plugin 协同增强。

核心概念

状态机

idle ──[pointerdown 命中]──→ pending

                  [move < threshold]  保持 pending
                  [move ≥ threshold]  → dragging

                  ┌── pointerup ──→ end ──→ idle

             dragging

                  └── Escape ────→ cancel(回滚)──→ idle

pointerdown 后不立即进入拖拽,而是等待移动距离超过 threshold(默认 3px),避免点击误触发。

位置写入策略(自动检测)

插件运行时自动检测环境,按优先级选择位置写入方式:

  1. 自定义回调 — 若提供 applyPosition,使用用户逻辑
  2. graph-plugin 集成 — 检测到 graph-plugin 时,通过 element.update({x, y}) 写入,自动触发依赖 edge 重绘
  3. 纯 engine 模式 — 直接调用 target.translate(newX, newY)

软感知,无硬依赖

Drag Plugin 通过 app.getPlugin('graph')app.getPlugin('selection') 运行时探测其他插件是否存在,不产生包级别的 import 依赖。未安装对应插件时自动降级为纯 engine 行为。

约束系统

三种约束按 axis → grid → bounds 顺序依次应用:

约束配置项说明
轴锁定axis'x' / 'y' / 'both'(默认 both)
网格吸附grid数字或 [gridX, gridY]
边界限制bounds{ minX, minY, maxX, maxY }
typescript
app.use(
  dragPlugin({
    constraint: {
      axis: 'x',
      grid: 20,
      bounds: {minX: 0, maxX: 800},
    },
  }),
);

多选联动

enableGroupDrag: true(默认)且已安装 selection-plugin 时:

  • 拖拽选中集合中的节点 → 所有选中节点一起移动
  • 拖拽未选中的节点 → 仅移动当前节点
  • 未安装 selection-plugin → 始终单节点拖拽

插件感知机制

被感知插件探测方式增强行为未安装时降级
graph-pluginapp.getPlugin('graph')通过 element.update({x,y}) 写入位置,自动触发 edge 依赖重绘target.translate() 直接移动
selection-pluginapp.getPlugin('selection')拖拽后调用 refreshOverlay() 刷新选框位置跳过(无选框需要刷新)
selection-pluginapp.getState('selection:selected')读取选中集合实现多选联动拖拽始终单节点拖拽

为什么由 drag 感知 selection,而不是反过来?

拖拽是主动修改位置的一方,它知道目标何时移动、移动了多少。让 selection-plugin 监听位置变化反而需要轮询或全局 hook,违反了「谁改谁通知」的原则。

基本使用

typescript
import {dragPlugin} from 'rendx-drag-plugin';

// 纯 engine 场景 — 所有节点可拖拽
app.use(dragPlugin());

// 配合 graph-plugin
app.use(
  dragPlugin({
    hitDelegate: target => {
      let node = target;
      while (node && node.type !== 4) {
        if (node.data?.role === 'port') return null;
        if (node.name && graph.has(node.name)) return node;
        node = node.parent;
      }
      return null;
    },
  }),
);

光标管理

交互状态光标
拖拽进行中grabbing
拖拽结束重置为默认

事件与状态

事件名触发时机关键负载
drag:start移动超过 thresholdtargets, origin
drag:move每帧 pointermovetargets, delta, totalDelta
drag:endpointerup 完成targets, totalDelta, startPositions, endPositions
drag:cancelEscape 或 cancel()targets
State Key类型说明
drag:draggingboolean是否正在拖拽
drag:targetsGraphics[]当前拖拽目标列表