npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@knotx/plugins-drag

v0.5.8

Published

Drag Plugin for Knotx

Readme

@knotx/plugins-drag

拖拽插件,为 KnotX 提供节点拖拽功能。

安装

npm install @knotx/plugins-drag

概述

Drag 插件为 KnotX 提供了强大的节点拖拽功能,支持惯性拖拽、边界限制、边缘滚动等高级特性。该插件基于 interactjs 库实现,提供了灵活的拖拽配置和流畅的拖拽体验。

实现原理

Drag 插件的核心实现原理:

  1. InteractJS 集成:使用 interactjs 库处理拖拽交互
  2. 拖拽变换器:支持动态修改拖拽配置的变换器系统
  3. 边缘滚动:拖拽到画布边缘时自动滚动画布
  4. 惯性拖拽:支持惯性拖拽效果,提供更自然的交互体验

依赖关系

核心依赖

  • @knotx/core:提供基础插件架构
  • @knotx/decorators:提供装饰器支持
  • interactjs:提供拖拽交互功能
  • rxjs:提供响应式编程支持

插件依赖

  • @knotx/plugins-canvas:获取画布变换状态和边缘滚动配置(可选)

API 文档

主要类

Drag

拖拽插件的主要类,继承自 BasePlugin

export class Drag extends BasePlugin {
  name = 'drag' as const
}

配置选项

DraggableOptions

export type DraggableOptions = Omit<InteractDraggableOptions, 'listeners'>

interface DraggableOptions {
  /** 惯性配置 */
  inertia?: {
    enabled?: boolean
    resistance?: number
    minSpeed?: number
    endSpeed?: number
    smoothEndDuration?: number
  }
  /** 修饰器配置 */
  modifiers?: Modifier[]
  /** 其他 InteractJS 配置 */
  [key: string]: any
}

插件数据 (PluginData)

Drag 插件提供以下数据:

interface PluginData {
  drag: {
    options: DraggableOptions
    registerOptionsTransformer: (transformer: DragOptionsTransformer) => () => void
  }
}

类型定义

DragOptionsTransformer

export interface DragTransformerContext {
  nodeId: string
  node: Node
  defaultOptions: DraggableOptions
  currentOptions: DraggableOptions
}

export type DragOptionsTransformer = (context: DragTransformerContext) => DraggableOptions | undefined

使用示例

基本用法

import { Drag } from '@knotx/plugins-drag'

const engine = new Engine({
  plugins: [Drag],
})

自定义拖拽配置

const engine = new Engine({
  plugins: [Drag],
})

// 获取插件数据
const dragData = engine.getPluginData('drag')

// 修改默认配置
dragData.options = {
  inertia: {
    enabled: true,
    resistance: 30,
    minSpeed: 200,
    endSpeed: 10,
  },
  modifiers: [
    interact.modifiers.restrictRect({
      restriction: 'parent',
      endOnly: true,
    }),
  ],
}

使用拖拽变换器

const engine = new Engine({
  plugins: [Drag],
})

const dragData = engine.getPluginData('drag')

// 注册拖拽变换器
const unregister = dragData.registerOptionsTransformer((context) => {
  const { nodeId, node, defaultOptions, currentOptions } = context

  // 根据节点类型或状态修改拖拽配置
  if (node.type === 'locked') {
    return {
      ...currentOptions,
      enabled: false, // 禁用拖拽
    }
  }

  if (node.type === 'slow') {
    return {
      ...currentOptions,
      inertia: {
        ...currentOptions.inertia,
        resistance: 100, // 增加阻力
      },
    }
  }

  return currentOptions
})

// 取消注册
unregister()

边界限制

const engine = new Engine({
  plugins: [Drag],
})

const dragData = engine.getPluginData('drag')

// 限制拖拽范围
dragData.options = {
  modifiers: [
    interact.modifiers.restrictRect({
      restriction: '.canvas-container',
      endOnly: true,
    }),
  ],
}

网格对齐

const engine = new Engine({
  plugins: [Drag],
})

const dragData = engine.getPluginData('drag')

// 网格对齐
dragData.options = {
  modifiers: [
    interact.modifiers.snap({
      targets: [
        interact.snappers.grid({ x: 20, y: 20 }),
      ],
      range: Infinity,
      relativePoints: [{ x: 0, y: 0 }],
    }),
  ],
}

与 Canvas 插件集成

import { Canvas } from '@knotx/plugins-canvas'
import { Drag } from '@knotx/plugins-drag'

const engine = new Engine({
  plugins: [Canvas, Drag],
  pluginConfig: {
    canvas: {
      minScale: 0.1,
      maxScale: 3,
    },
  },
})

// 启用边缘滚动
const canvasData = engine.getPluginData('canvas')
canvasData.edgeScroll.setConfig({
  enabled: true,
  edgeSize: 100,
  maxSpeed: 10,
})

高级功能

动态拖拽配置

class DynamicDragPlugin extends BasePlugin {
  @inject.drag.registerOptionsTransformer()
  registerOptionsTransformer!: (transformer: DragOptionsTransformer) => () => void

  @inject.selection.selected()
  selected!: SelectionSelectedItem[]

  @OnInit
  init() {
    this.registerOptionsTransformer((context) => {
      const { nodeId, currentOptions } = context

      // 多选拖拽时的特殊配置
      const isMultiSelected = this.selected.length > 1
        && this.selected.some(item => item.id === nodeId)

      if (isMultiSelected) {
        return {
          ...currentOptions,
          inertia: {
            ...currentOptions.inertia,
            enabled: false, // 多选时禁用惯性
          },
        }
      }

      return currentOptions
    })
  }
}

自定义拖拽修饰器

const engine = new Engine({
  plugins: [Drag],
})

const dragData = engine.getPluginData('drag')

// 创建自定义修饰器
const customModifier = {
  set(coords: any) {
    // 自定义位置计算逻辑
    coords.x = Math.round(coords.x / 10) * 10 // 10px 网格对齐
    coords.y = Math.round(coords.y / 10) * 10
    return coords
  },
}

dragData.options = {
  modifiers: [customModifier],
}

拖拽状态监听

class DragStatusPlugin extends BasePlugin {
  @inject.canvas.edgeScroll()
  edgeScroll!: PluginData['canvas']['edgeScroll']

  @subscribe.drag.isDragging()
  onDragStatusChange(isDragging: boolean) {
    if (isDragging) {
      console.log('开始拖拽')
      // 拖拽开始时启用边缘滚动
      this.edgeScroll.setConfig({ enabled: true })
    }
    else {
      console.log('结束拖拽')
      // 拖拽结束时禁用边缘滚动
      this.edgeScroll.setConfig({ enabled: false })
    }
  }
}

文件目录结构

packages/plugins-drag/
├── src/
│   ├── drag.tsx                # 主要实现文件
│   └── index.ts               # 导出文件
├── dist/                      # 构建输出目录
├── package.json              # 包配置文件
├── build.config.ts           # 构建配置
├── tsconfig.json             # TypeScript 配置
├── eslint.config.mjs         # ESLint 配置
└── CHANGELOG.md              # 更新日志

核心文件说明

  • drag.tsx:包含 Drag 插件的主要实现,包括 InteractJS 集成、拖拽变换器系统和边缘滚动处理
  • index.ts:导出 Drag 类和相关类型定义

最佳实践

性能优化

  1. 合理使用惯性:惯性效果虽然提供更好的用户体验,但在大量节点时可能影响性能
  2. 限制拖拽范围:使用 restrictRect 修饰器限制拖拽范围,避免节点拖拽到不合理的位置
  3. 批量操作:结合 @knotx/plugins-batch 插件优化批量拖拽操作

用户体验

  1. 视觉反馈:拖拽时提供清晰的视觉反馈,如阴影、透明度变化等
  2. 网格对齐:在需要精确定位的场景中启用网格对齐
  3. 边缘滚动:启用边缘滚动功能,改善大画布中的拖拽体验

注意事项

  1. 事件冲突:与其他交互插件(如选择)可能存在事件冲突,注意事件优先级
  2. 内存管理:及时清理不需要的拖拽变换器,避免内存泄漏
  3. 性能考虑:大量节点时,拖拽操作可能影响性能,考虑使用虚拟化
  4. 移动端适配:在移动端需要考虑触摸事件的处理

许可证

MIT