@knotx/plugins-drag 0.4.12 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +376 -0
- package/README.md +376 -0
- package/package.json +10 -10
package/README.en.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# @knotx/plugins-drag
|
|
2
|
+
|
|
3
|
+
Drag plugin that provides node dragging functionality for KnotX.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/plugins-drag
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
The Drag plugin provides powerful node dragging functionality for KnotX, supporting inertia dragging, boundary restrictions, edge scrolling, and other advanced features. This plugin is built on the `interactjs` library and offers flexible drag configuration and smooth dragging experience.
|
|
14
|
+
|
|
15
|
+
## Implementation Principle
|
|
16
|
+
|
|
17
|
+
The core implementation principles of the Drag plugin:
|
|
18
|
+
|
|
19
|
+
1. **InteractJS Integration**: Uses the `interactjs` library to handle drag interactions
|
|
20
|
+
2. **Drag Transformers**: Supports transformer system for dynamically modifying drag configurations
|
|
21
|
+
3. **Edge Scrolling**: Automatically scrolls the canvas when dragging to canvas edges
|
|
22
|
+
4. **Inertia Dragging**: Supports inertia drag effects for more natural interaction experience
|
|
23
|
+
|
|
24
|
+
## Dependencies
|
|
25
|
+
|
|
26
|
+
### Core Dependencies
|
|
27
|
+
- `@knotx/core`: Provides base plugin architecture
|
|
28
|
+
- `@knotx/decorators`: Provides decorator support
|
|
29
|
+
- `interactjs`: Provides drag interaction functionality
|
|
30
|
+
- `@interactjs/actions`: InteractJS action modules
|
|
31
|
+
- `@interactjs/core`: InteractJS core module
|
|
32
|
+
- `@interactjs/modifiers`: InteractJS modifier modules
|
|
33
|
+
- `@interactjs/types`: InteractJS type definitions
|
|
34
|
+
- `rxjs`: Provides reactive programming support
|
|
35
|
+
|
|
36
|
+
### Plugin Dependencies
|
|
37
|
+
- `@knotx/plugins-canvas`: Retrieves canvas transform state and edge scroll configuration (optional)
|
|
38
|
+
|
|
39
|
+
## API Documentation
|
|
40
|
+
|
|
41
|
+
### Main Classes
|
|
42
|
+
|
|
43
|
+
#### Drag
|
|
44
|
+
|
|
45
|
+
The main class of the Drag plugin, extending `BasePlugin`.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
export class Drag extends BasePlugin {
|
|
49
|
+
name = 'drag' as const
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Configuration Options
|
|
54
|
+
|
|
55
|
+
#### DraggableOptions
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
export type DraggableOptions = Omit<InteractDraggableOptions, 'listeners'>
|
|
59
|
+
|
|
60
|
+
interface DraggableOptions {
|
|
61
|
+
/** Inertia configuration */
|
|
62
|
+
inertia?: {
|
|
63
|
+
enabled?: boolean
|
|
64
|
+
resistance?: number
|
|
65
|
+
minSpeed?: number
|
|
66
|
+
endSpeed?: number
|
|
67
|
+
smoothEndDuration?: number
|
|
68
|
+
}
|
|
69
|
+
/** Modifier configuration */
|
|
70
|
+
modifiers?: Modifier[]
|
|
71
|
+
/** Other InteractJS configurations */
|
|
72
|
+
[key: string]: any
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Plugin Data (PluginData)
|
|
77
|
+
|
|
78
|
+
The Drag plugin provides the following data:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interface PluginData {
|
|
82
|
+
drag: {
|
|
83
|
+
options: DraggableOptions
|
|
84
|
+
registerOptionsTransformer: (transformer: DragOptionsTransformer) => () => void
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Type Definitions
|
|
90
|
+
|
|
91
|
+
#### DragOptionsTransformer
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
export interface DragTransformerContext {
|
|
95
|
+
nodeId: string
|
|
96
|
+
node: Node
|
|
97
|
+
defaultOptions: DraggableOptions
|
|
98
|
+
currentOptions: DraggableOptions
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type DragOptionsTransformer = (context: DragTransformerContext) => DraggableOptions | undefined
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Usage Examples
|
|
105
|
+
|
|
106
|
+
### Basic Usage
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { Drag } from '@knotx/plugins-drag'
|
|
110
|
+
|
|
111
|
+
const engine = new Engine({
|
|
112
|
+
plugins: [Drag],
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Custom Drag Configuration
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const engine = new Engine({
|
|
120
|
+
plugins: [Drag],
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Get plugin data
|
|
124
|
+
const dragData = engine.getPluginData('drag')
|
|
125
|
+
|
|
126
|
+
// Modify default configuration
|
|
127
|
+
dragData.options = {
|
|
128
|
+
inertia: {
|
|
129
|
+
enabled: true,
|
|
130
|
+
resistance: 30,
|
|
131
|
+
minSpeed: 200,
|
|
132
|
+
endSpeed: 10,
|
|
133
|
+
},
|
|
134
|
+
modifiers: [
|
|
135
|
+
interact.modifiers.restrictRect({
|
|
136
|
+
restriction: 'parent',
|
|
137
|
+
endOnly: true,
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Using Drag Transformers
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const engine = new Engine({
|
|
147
|
+
plugins: [Drag],
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const dragData = engine.getPluginData('drag')
|
|
151
|
+
|
|
152
|
+
// Register drag transformer
|
|
153
|
+
const unregister = dragData.registerOptionsTransformer((context) => {
|
|
154
|
+
const { nodeId, node, defaultOptions, currentOptions } = context
|
|
155
|
+
|
|
156
|
+
// Modify drag configuration based on node type or state
|
|
157
|
+
if (node.type === 'locked') {
|
|
158
|
+
return {
|
|
159
|
+
...currentOptions,
|
|
160
|
+
enabled: false, // Disable dragging
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (node.type === 'slow') {
|
|
165
|
+
return {
|
|
166
|
+
...currentOptions,
|
|
167
|
+
inertia: {
|
|
168
|
+
...currentOptions.inertia,
|
|
169
|
+
resistance: 100, // Increase resistance
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return currentOptions
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// Unregister
|
|
178
|
+
unregister()
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Boundary Restrictions
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const engine = new Engine({
|
|
185
|
+
plugins: [Drag],
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const dragData = engine.getPluginData('drag')
|
|
189
|
+
|
|
190
|
+
// Restrict drag area
|
|
191
|
+
dragData.options = {
|
|
192
|
+
modifiers: [
|
|
193
|
+
interact.modifiers.restrictRect({
|
|
194
|
+
restriction: '.canvas-container',
|
|
195
|
+
endOnly: true,
|
|
196
|
+
}),
|
|
197
|
+
],
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Grid Snapping
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const engine = new Engine({
|
|
205
|
+
plugins: [Drag],
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const dragData = engine.getPluginData('drag')
|
|
209
|
+
|
|
210
|
+
// Grid snapping
|
|
211
|
+
dragData.options = {
|
|
212
|
+
modifiers: [
|
|
213
|
+
interact.modifiers.snap({
|
|
214
|
+
targets: [
|
|
215
|
+
interact.snappers.grid({ x: 20, y: 20 }),
|
|
216
|
+
],
|
|
217
|
+
range: Infinity,
|
|
218
|
+
relativePoints: [{ x: 0, y: 0 }],
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Integration with Canvas Plugin
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { Canvas } from '@knotx/plugins-canvas'
|
|
228
|
+
import { Drag } from '@knotx/plugins-drag'
|
|
229
|
+
|
|
230
|
+
const engine = new Engine({
|
|
231
|
+
plugins: [Canvas, Drag],
|
|
232
|
+
pluginConfig: {
|
|
233
|
+
canvas: {
|
|
234
|
+
minScale: 0.1,
|
|
235
|
+
maxScale: 3,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// Enable edge scrolling
|
|
241
|
+
const canvasData = engine.getPluginData('canvas')
|
|
242
|
+
canvasData.edgeScroll.setConfig({
|
|
243
|
+
enabled: true,
|
|
244
|
+
edgeSize: 100,
|
|
245
|
+
maxSpeed: 10,
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Advanced Features
|
|
250
|
+
|
|
251
|
+
### Dynamic Drag Configuration
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
class DynamicDragPlugin extends BasePlugin {
|
|
255
|
+
@inject.drag.registerOptionsTransformer()
|
|
256
|
+
registerOptionsTransformer!: (transformer: DragOptionsTransformer) => () => void
|
|
257
|
+
|
|
258
|
+
@inject.selection.selected()
|
|
259
|
+
selected!: SelectionSelectedItem[]
|
|
260
|
+
|
|
261
|
+
@OnInit
|
|
262
|
+
init() {
|
|
263
|
+
this.registerOptionsTransformer((context) => {
|
|
264
|
+
const { nodeId, currentOptions } = context
|
|
265
|
+
|
|
266
|
+
// Special configuration for multi-selection dragging
|
|
267
|
+
const isMultiSelected = this.selected.length > 1
|
|
268
|
+
&& this.selected.some(item => item.id === nodeId)
|
|
269
|
+
|
|
270
|
+
if (isMultiSelected) {
|
|
271
|
+
return {
|
|
272
|
+
...currentOptions,
|
|
273
|
+
inertia: {
|
|
274
|
+
...currentOptions.inertia,
|
|
275
|
+
enabled: false, // Disable inertia for multi-selection
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return currentOptions
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Custom Drag Modifiers
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
const engine = new Engine({
|
|
290
|
+
plugins: [Drag],
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
const dragData = engine.getPluginData('drag')
|
|
294
|
+
|
|
295
|
+
// Create custom modifier
|
|
296
|
+
const customModifier = {
|
|
297
|
+
set(coords: any) {
|
|
298
|
+
// Custom position calculation logic
|
|
299
|
+
coords.x = Math.round(coords.x / 10) * 10 // 10px grid alignment
|
|
300
|
+
coords.y = Math.round(coords.y / 10) * 10
|
|
301
|
+
return coords
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
dragData.options = {
|
|
306
|
+
modifiers: [customModifier],
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Drag Status Monitoring
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
class DragStatusPlugin extends BasePlugin {
|
|
314
|
+
@inject.canvas.edgeScroll()
|
|
315
|
+
edgeScroll!: PluginData['canvas']['edgeScroll']
|
|
316
|
+
|
|
317
|
+
@subscribe.drag.isDragging()
|
|
318
|
+
onDragStatusChange(isDragging: boolean) {
|
|
319
|
+
if (isDragging) {
|
|
320
|
+
console.log('Start dragging')
|
|
321
|
+
// Enable edge scrolling when dragging starts
|
|
322
|
+
this.edgeScroll.setConfig({ enabled: true })
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
console.log('End dragging')
|
|
326
|
+
// Disable edge scrolling when dragging ends
|
|
327
|
+
this.edgeScroll.setConfig({ enabled: false })
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## File Directory Structure
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
packages/plugins-drag/
|
|
337
|
+
├── src/
|
|
338
|
+
│ ├── drag.tsx # Main implementation file
|
|
339
|
+
│ └── index.ts # Export file
|
|
340
|
+
├── dist/ # Build output directory
|
|
341
|
+
├── package.json # Package configuration
|
|
342
|
+
├── build.config.ts # Build configuration
|
|
343
|
+
├── tsconfig.json # TypeScript configuration
|
|
344
|
+
├── eslint.config.mjs # ESLint configuration
|
|
345
|
+
└── CHANGELOG.md # Changelog
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Core Files Description
|
|
349
|
+
|
|
350
|
+
- **drag.tsx**: Contains the main implementation of the Drag plugin, including InteractJS integration, drag transformer system, and edge scrolling handling
|
|
351
|
+
- **index.ts**: Exports the Drag class and related type definitions
|
|
352
|
+
|
|
353
|
+
## Best Practices
|
|
354
|
+
|
|
355
|
+
### Performance Optimization
|
|
356
|
+
|
|
357
|
+
1. **Reasonable Use of Inertia**: Inertia effects provide better user experience but may impact performance with many nodes
|
|
358
|
+
2. **Restrict Drag Area**: Use `restrictRect` modifier to limit drag area and prevent nodes from being dragged to unreasonable positions
|
|
359
|
+
3. **Batch Operations**: Combine with `@knotx/plugins-batch` plugin to optimize batch drag operations
|
|
360
|
+
|
|
361
|
+
### User Experience
|
|
362
|
+
|
|
363
|
+
1. **Visual Feedback**: Provide clear visual feedback during dragging, such as shadows, transparency changes, etc.
|
|
364
|
+
2. **Grid Alignment**: Enable grid alignment in scenarios requiring precise positioning
|
|
365
|
+
3. **Edge Scrolling**: Enable edge scrolling functionality to improve drag experience in large canvases
|
|
366
|
+
|
|
367
|
+
## Notes
|
|
368
|
+
|
|
369
|
+
1. **Event Conflicts**: May have event conflicts with other interaction plugins (like selection); pay attention to event priority
|
|
370
|
+
2. **Memory Management**: Clean up unnecessary drag transformers promptly to avoid memory leaks
|
|
371
|
+
3. **Performance Considerations**: With many nodes, drag operations may impact performance; consider using virtualization
|
|
372
|
+
4. **Mobile Adaptation**: Consider touch event handling on mobile devices
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# @knotx/plugins-drag
|
|
2
|
+
|
|
3
|
+
拖拽插件,为 KnotX 提供节点拖拽功能。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/plugins-drag
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 概述
|
|
12
|
+
|
|
13
|
+
Drag 插件为 KnotX 提供了强大的节点拖拽功能,支持惯性拖拽、边界限制、边缘滚动等高级特性。该插件基于 `interactjs` 库实现,提供了灵活的拖拽配置和流畅的拖拽体验。
|
|
14
|
+
|
|
15
|
+
## 实现原理
|
|
16
|
+
|
|
17
|
+
Drag 插件的核心实现原理:
|
|
18
|
+
|
|
19
|
+
1. **InteractJS 集成**:使用 `interactjs` 库处理拖拽交互
|
|
20
|
+
2. **拖拽变换器**:支持动态修改拖拽配置的变换器系统
|
|
21
|
+
3. **边缘滚动**:拖拽到画布边缘时自动滚动画布
|
|
22
|
+
4. **惯性拖拽**:支持惯性拖拽效果,提供更自然的交互体验
|
|
23
|
+
|
|
24
|
+
## 依赖关系
|
|
25
|
+
|
|
26
|
+
### 核心依赖
|
|
27
|
+
- `@knotx/core`:提供基础插件架构
|
|
28
|
+
- `@knotx/decorators`:提供装饰器支持
|
|
29
|
+
- `interactjs`:提供拖拽交互功能
|
|
30
|
+
- `@interactjs/actions`:InteractJS 动作模块
|
|
31
|
+
- `@interactjs/core`:InteractJS 核心模块
|
|
32
|
+
- `@interactjs/modifiers`:InteractJS 修饰器模块
|
|
33
|
+
- `@interactjs/types`:InteractJS 类型定义
|
|
34
|
+
- `rxjs`:提供响应式编程支持
|
|
35
|
+
|
|
36
|
+
### 插件依赖
|
|
37
|
+
- `@knotx/plugins-canvas`:获取画布变换状态和边缘滚动配置(可选)
|
|
38
|
+
|
|
39
|
+
## API 文档
|
|
40
|
+
|
|
41
|
+
### 主要类
|
|
42
|
+
|
|
43
|
+
#### Drag
|
|
44
|
+
|
|
45
|
+
拖拽插件的主要类,继承自 `BasePlugin`。
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
export class Drag extends BasePlugin {
|
|
49
|
+
name = 'drag' as const
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 配置选项
|
|
54
|
+
|
|
55
|
+
#### DraggableOptions
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
export type DraggableOptions = Omit<InteractDraggableOptions, 'listeners'>
|
|
59
|
+
|
|
60
|
+
interface DraggableOptions {
|
|
61
|
+
/** 惯性配置 */
|
|
62
|
+
inertia?: {
|
|
63
|
+
enabled?: boolean
|
|
64
|
+
resistance?: number
|
|
65
|
+
minSpeed?: number
|
|
66
|
+
endSpeed?: number
|
|
67
|
+
smoothEndDuration?: number
|
|
68
|
+
}
|
|
69
|
+
/** 修饰器配置 */
|
|
70
|
+
modifiers?: Modifier[]
|
|
71
|
+
/** 其他 InteractJS 配置 */
|
|
72
|
+
[key: string]: any
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 插件数据 (PluginData)
|
|
77
|
+
|
|
78
|
+
Drag 插件提供以下数据:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interface PluginData {
|
|
82
|
+
drag: {
|
|
83
|
+
options: DraggableOptions
|
|
84
|
+
registerOptionsTransformer: (transformer: DragOptionsTransformer) => () => void
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 类型定义
|
|
90
|
+
|
|
91
|
+
#### DragOptionsTransformer
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
export interface DragTransformerContext {
|
|
95
|
+
nodeId: string
|
|
96
|
+
node: Node
|
|
97
|
+
defaultOptions: DraggableOptions
|
|
98
|
+
currentOptions: DraggableOptions
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type DragOptionsTransformer = (context: DragTransformerContext) => DraggableOptions | undefined
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 使用示例
|
|
105
|
+
|
|
106
|
+
### 基本用法
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { Drag } from '@knotx/plugins-drag'
|
|
110
|
+
|
|
111
|
+
const engine = new Engine({
|
|
112
|
+
plugins: [Drag],
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 自定义拖拽配置
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const engine = new Engine({
|
|
120
|
+
plugins: [Drag],
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// 获取插件数据
|
|
124
|
+
const dragData = engine.getPluginData('drag')
|
|
125
|
+
|
|
126
|
+
// 修改默认配置
|
|
127
|
+
dragData.options = {
|
|
128
|
+
inertia: {
|
|
129
|
+
enabled: true,
|
|
130
|
+
resistance: 30,
|
|
131
|
+
minSpeed: 200,
|
|
132
|
+
endSpeed: 10,
|
|
133
|
+
},
|
|
134
|
+
modifiers: [
|
|
135
|
+
interact.modifiers.restrictRect({
|
|
136
|
+
restriction: 'parent',
|
|
137
|
+
endOnly: true,
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 使用拖拽变换器
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const engine = new Engine({
|
|
147
|
+
plugins: [Drag],
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const dragData = engine.getPluginData('drag')
|
|
151
|
+
|
|
152
|
+
// 注册拖拽变换器
|
|
153
|
+
const unregister = dragData.registerOptionsTransformer((context) => {
|
|
154
|
+
const { nodeId, node, defaultOptions, currentOptions } = context
|
|
155
|
+
|
|
156
|
+
// 根据节点类型或状态修改拖拽配置
|
|
157
|
+
if (node.type === 'locked') {
|
|
158
|
+
return {
|
|
159
|
+
...currentOptions,
|
|
160
|
+
enabled: false, // 禁用拖拽
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (node.type === 'slow') {
|
|
165
|
+
return {
|
|
166
|
+
...currentOptions,
|
|
167
|
+
inertia: {
|
|
168
|
+
...currentOptions.inertia,
|
|
169
|
+
resistance: 100, // 增加阻力
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return currentOptions
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// 取消注册
|
|
178
|
+
unregister()
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 边界限制
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const engine = new Engine({
|
|
185
|
+
plugins: [Drag],
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const dragData = engine.getPluginData('drag')
|
|
189
|
+
|
|
190
|
+
// 限制拖拽范围
|
|
191
|
+
dragData.options = {
|
|
192
|
+
modifiers: [
|
|
193
|
+
interact.modifiers.restrictRect({
|
|
194
|
+
restriction: '.canvas-container',
|
|
195
|
+
endOnly: true,
|
|
196
|
+
}),
|
|
197
|
+
],
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 网格对齐
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const engine = new Engine({
|
|
205
|
+
plugins: [Drag],
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const dragData = engine.getPluginData('drag')
|
|
209
|
+
|
|
210
|
+
// 网格对齐
|
|
211
|
+
dragData.options = {
|
|
212
|
+
modifiers: [
|
|
213
|
+
interact.modifiers.snap({
|
|
214
|
+
targets: [
|
|
215
|
+
interact.snappers.grid({ x: 20, y: 20 }),
|
|
216
|
+
],
|
|
217
|
+
range: Infinity,
|
|
218
|
+
relativePoints: [{ x: 0, y: 0 }],
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 与 Canvas 插件集成
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { Canvas } from '@knotx/plugins-canvas'
|
|
228
|
+
import { Drag } from '@knotx/plugins-drag'
|
|
229
|
+
|
|
230
|
+
const engine = new Engine({
|
|
231
|
+
plugins: [Canvas, Drag],
|
|
232
|
+
pluginConfig: {
|
|
233
|
+
canvas: {
|
|
234
|
+
minScale: 0.1,
|
|
235
|
+
maxScale: 3,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// 启用边缘滚动
|
|
241
|
+
const canvasData = engine.getPluginData('canvas')
|
|
242
|
+
canvasData.edgeScroll.setConfig({
|
|
243
|
+
enabled: true,
|
|
244
|
+
edgeSize: 100,
|
|
245
|
+
maxSpeed: 10,
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## 高级功能
|
|
250
|
+
|
|
251
|
+
### 动态拖拽配置
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
class DynamicDragPlugin extends BasePlugin {
|
|
255
|
+
@inject.drag.registerOptionsTransformer()
|
|
256
|
+
registerOptionsTransformer!: (transformer: DragOptionsTransformer) => () => void
|
|
257
|
+
|
|
258
|
+
@inject.selection.selected()
|
|
259
|
+
selected!: SelectionSelectedItem[]
|
|
260
|
+
|
|
261
|
+
@OnInit
|
|
262
|
+
init() {
|
|
263
|
+
this.registerOptionsTransformer((context) => {
|
|
264
|
+
const { nodeId, currentOptions } = context
|
|
265
|
+
|
|
266
|
+
// 多选拖拽时的特殊配置
|
|
267
|
+
const isMultiSelected = this.selected.length > 1
|
|
268
|
+
&& this.selected.some(item => item.id === nodeId)
|
|
269
|
+
|
|
270
|
+
if (isMultiSelected) {
|
|
271
|
+
return {
|
|
272
|
+
...currentOptions,
|
|
273
|
+
inertia: {
|
|
274
|
+
...currentOptions.inertia,
|
|
275
|
+
enabled: false, // 多选时禁用惯性
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return currentOptions
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### 自定义拖拽修饰器
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
const engine = new Engine({
|
|
290
|
+
plugins: [Drag],
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
const dragData = engine.getPluginData('drag')
|
|
294
|
+
|
|
295
|
+
// 创建自定义修饰器
|
|
296
|
+
const customModifier = {
|
|
297
|
+
set(coords: any) {
|
|
298
|
+
// 自定义位置计算逻辑
|
|
299
|
+
coords.x = Math.round(coords.x / 10) * 10 // 10px 网格对齐
|
|
300
|
+
coords.y = Math.round(coords.y / 10) * 10
|
|
301
|
+
return coords
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
dragData.options = {
|
|
306
|
+
modifiers: [customModifier],
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### 拖拽状态监听
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
class DragStatusPlugin extends BasePlugin {
|
|
314
|
+
@inject.canvas.edgeScroll()
|
|
315
|
+
edgeScroll!: PluginData['canvas']['edgeScroll']
|
|
316
|
+
|
|
317
|
+
@subscribe.drag.isDragging()
|
|
318
|
+
onDragStatusChange(isDragging: boolean) {
|
|
319
|
+
if (isDragging) {
|
|
320
|
+
console.log('开始拖拽')
|
|
321
|
+
// 拖拽开始时启用边缘滚动
|
|
322
|
+
this.edgeScroll.setConfig({ enabled: true })
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
console.log('结束拖拽')
|
|
326
|
+
// 拖拽结束时禁用边缘滚动
|
|
327
|
+
this.edgeScroll.setConfig({ enabled: false })
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## 文件目录结构
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
packages/plugins-drag/
|
|
337
|
+
├── src/
|
|
338
|
+
│ ├── drag.tsx # 主要实现文件
|
|
339
|
+
│ └── index.ts # 导出文件
|
|
340
|
+
├── dist/ # 构建输出目录
|
|
341
|
+
├── package.json # 包配置文件
|
|
342
|
+
├── build.config.ts # 构建配置
|
|
343
|
+
├── tsconfig.json # TypeScript 配置
|
|
344
|
+
├── eslint.config.mjs # ESLint 配置
|
|
345
|
+
└── CHANGELOG.md # 更新日志
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 核心文件说明
|
|
349
|
+
|
|
350
|
+
- **drag.tsx**:包含 Drag 插件的主要实现,包括 InteractJS 集成、拖拽变换器系统和边缘滚动处理
|
|
351
|
+
- **index.ts**:导出 Drag 类和相关类型定义
|
|
352
|
+
|
|
353
|
+
## 最佳实践
|
|
354
|
+
|
|
355
|
+
### 性能优化
|
|
356
|
+
|
|
357
|
+
1. **合理使用惯性**:惯性效果虽然提供更好的用户体验,但在大量节点时可能影响性能
|
|
358
|
+
2. **限制拖拽范围**:使用 `restrictRect` 修饰器限制拖拽范围,避免节点拖拽到不合理的位置
|
|
359
|
+
3. **批量操作**:结合 `@knotx/plugins-batch` 插件优化批量拖拽操作
|
|
360
|
+
|
|
361
|
+
### 用户体验
|
|
362
|
+
|
|
363
|
+
1. **视觉反馈**:拖拽时提供清晰的视觉反馈,如阴影、透明度变化等
|
|
364
|
+
2. **网格对齐**:在需要精确定位的场景中启用网格对齐
|
|
365
|
+
3. **边缘滚动**:启用边缘滚动功能,改善大画布中的拖拽体验
|
|
366
|
+
|
|
367
|
+
## 注意事项
|
|
368
|
+
|
|
369
|
+
1. **事件冲突**:与其他交互插件(如选择)可能存在事件冲突,注意事件优先级
|
|
370
|
+
2. **内存管理**:及时清理不需要的拖拽变换器,避免内存泄漏
|
|
371
|
+
3. **性能考虑**:大量节点时,拖拽操作可能影响性能,考虑使用虚拟化
|
|
372
|
+
4. **移动端适配**:在移动端需要考虑触摸事件的处理
|
|
373
|
+
|
|
374
|
+
## 许可证
|
|
375
|
+
|
|
376
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knotx/plugins-drag",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Drag Plugin for Knotx",
|
|
5
5
|
"author": "boenfu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@knotx/jsx": "0.4.
|
|
32
|
-
"@knotx/plugins-canvas": "0.4.
|
|
31
|
+
"@knotx/jsx": "0.4.13",
|
|
32
|
+
"@knotx/plugins-canvas": "0.4.13"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@interactjs/actions": "^1.10.27",
|
|
@@ -38,15 +38,15 @@
|
|
|
38
38
|
"@interactjs/types": "^1.10.27",
|
|
39
39
|
"interactjs": "^1.10.27",
|
|
40
40
|
"rxjs": "^7.8.1",
|
|
41
|
-
"@knotx/core": "0.4.
|
|
42
|
-
"@knotx/decorators": "0.4.
|
|
41
|
+
"@knotx/core": "0.4.13",
|
|
42
|
+
"@knotx/decorators": "0.4.13"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@knotx/build-config": "0.4.
|
|
46
|
-
"@knotx/eslint-config": "0.4.
|
|
47
|
-
"@knotx/jsx": "0.4.
|
|
48
|
-
"@knotx/plugins-canvas": "0.4.
|
|
49
|
-
"@knotx/typescript-config": "0.4.
|
|
45
|
+
"@knotx/build-config": "0.4.13",
|
|
46
|
+
"@knotx/eslint-config": "0.4.13",
|
|
47
|
+
"@knotx/jsx": "0.4.13",
|
|
48
|
+
"@knotx/plugins-canvas": "0.4.13",
|
|
49
|
+
"@knotx/typescript-config": "0.4.13"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"build": "unbuild",
|