@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 插件的核心实现原理:
- InteractJS 集成:使用
interactjs库处理拖拽交互 - 拖拽变换器:支持动态修改拖拽配置的变换器系统
- 边缘滚动:拖拽到画布边缘时自动滚动画布
- 惯性拖拽:支持惯性拖拽效果,提供更自然的交互体验
依赖关系
核心依赖
@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 类和相关类型定义
最佳实践
性能优化
- 合理使用惯性:惯性效果虽然提供更好的用户体验,但在大量节点时可能影响性能
- 限制拖拽范围:使用
restrictRect修饰器限制拖拽范围,避免节点拖拽到不合理的位置 - 批量操作:结合
@knotx/plugins-batch插件优化批量拖拽操作
用户体验
- 视觉反馈:拖拽时提供清晰的视觉反馈,如阴影、透明度变化等
- 网格对齐:在需要精确定位的场景中启用网格对齐
- 边缘滚动:启用边缘滚动功能,改善大画布中的拖拽体验
注意事项
- 事件冲突:与其他交互插件(如选择)可能存在事件冲突,注意事件优先级
- 内存管理:及时清理不需要的拖拽变换器,避免内存泄漏
- 性能考虑:大量节点时,拖拽操作可能影响性能,考虑使用虚拟化
- 移动端适配:在移动端需要考虑触摸事件的处理
许可证
MIT
