@knotx/plugins-selection 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 +344 -0
- package/README.md +344 -0
- package/package.json +8 -8
package/README.en.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# @knotx/plugins-selection
|
|
2
|
+
|
|
3
|
+
Selection plugin that provides element selection functionality for KnotX.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/plugins-selection
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
The Selection plugin provides powerful element selection functionality for KnotX, supporting mouse selection, keyboard operations, and programmatic selection. This plugin is built on the `@knotx/viselect` library and offers flexible selection rules and rich selection events.
|
|
14
|
+
|
|
15
|
+
## Implementation Principle
|
|
16
|
+
|
|
17
|
+
The core implementation principles of the Selection plugin:
|
|
18
|
+
|
|
19
|
+
1. **Selection Area Management**: Uses the `@knotx/viselect` library to create selection areas with drag selection support
|
|
20
|
+
2. **Rule System**: Defines selection behavior for different element types through a rule system
|
|
21
|
+
3. **Event Handling**: Provides complete selection event lifecycle management
|
|
22
|
+
4. **State Synchronization**: Synchronizes with canvas transform state to ensure selection area accuracy
|
|
23
|
+
|
|
24
|
+
## Dependencies
|
|
25
|
+
|
|
26
|
+
### Core Dependencies
|
|
27
|
+
- `@knotx/core`: Provides base plugin architecture
|
|
28
|
+
- `@knotx/decorators`: Provides decorator support
|
|
29
|
+
- `@knotx/viselect`: Provides selection area functionality
|
|
30
|
+
|
|
31
|
+
### Plugin Dependencies
|
|
32
|
+
- `@knotx/plugins-canvas`: Retrieves canvas transform state and container information (optional)
|
|
33
|
+
|
|
34
|
+
## API Documentation
|
|
35
|
+
|
|
36
|
+
### Main Classes
|
|
37
|
+
|
|
38
|
+
#### Selection
|
|
39
|
+
|
|
40
|
+
The main class of the Selection plugin, extending `BasePlugin`.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
export class Selection extends BasePlugin<'selection', SelectionConfig> {
|
|
44
|
+
name = 'selection' as const
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Configuration Options
|
|
49
|
+
|
|
50
|
+
#### SelectionConfig
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
export interface SelectionConfig {
|
|
54
|
+
/** Selection area class name */
|
|
55
|
+
selectionAreaClassName?: string
|
|
56
|
+
/** Enable drag selection */
|
|
57
|
+
enableDrag?: boolean
|
|
58
|
+
/** Selection rules */
|
|
59
|
+
rules?: SelectionRule[]
|
|
60
|
+
/** Disable default rules */
|
|
61
|
+
disableDefaultRules?: boolean
|
|
62
|
+
/** Selection container */
|
|
63
|
+
container?: string
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### SelectionRule
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
export interface SelectionRule {
|
|
71
|
+
/** Resource type */
|
|
72
|
+
type: string
|
|
73
|
+
/** Element class name */
|
|
74
|
+
className: string
|
|
75
|
+
/** ID getter function */
|
|
76
|
+
idGetter: (element: Element) => string
|
|
77
|
+
/** Active state class name */
|
|
78
|
+
activeClassName?: string
|
|
79
|
+
/** Selection callback */
|
|
80
|
+
onSelected?: (context: SelectionContext) => boolean
|
|
81
|
+
/** Data selector type */
|
|
82
|
+
dataSelectorType?: string
|
|
83
|
+
/** Enable rule */
|
|
84
|
+
enabled?: boolean
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Plugin Data (PluginData)
|
|
89
|
+
|
|
90
|
+
The Selection plugin provides the following data:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
interface PluginData {
|
|
94
|
+
selection: {
|
|
95
|
+
selected: SelectionSelectedItem[]
|
|
96
|
+
registerRules: (rules: SelectionRule[]) => () => void
|
|
97
|
+
setRuleEnabled: (type: string, enabled: boolean) => void
|
|
98
|
+
setClearSelectionBeforeStart: (isClearSelectionBeforeStart: boolean) => void
|
|
99
|
+
setElementOverlap: (overlap: OverlapMode) => void
|
|
100
|
+
resolveSelectables: () => void
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Plugin Tools (PluginTools)
|
|
106
|
+
|
|
107
|
+
The Selection plugin provides the following tool methods:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface PluginTools {
|
|
111
|
+
selection: {
|
|
112
|
+
select: (items: SelectionSelectedItem[]) => void
|
|
113
|
+
deselect: (items: SelectionSelectedItem[]) => void
|
|
114
|
+
getSelected: () => SelectionSelectedItem[]
|
|
115
|
+
clearSelection: () => void
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Type Definitions
|
|
121
|
+
|
|
122
|
+
#### SelectionSelectedItem
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
export interface SelectionSelectedItem {
|
|
126
|
+
type: string
|
|
127
|
+
id: string
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Usage Examples
|
|
132
|
+
|
|
133
|
+
### Basic Usage
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { Selection } from '@knotx/plugins-selection'
|
|
137
|
+
|
|
138
|
+
const engine = new Engine({
|
|
139
|
+
plugins: [Selection],
|
|
140
|
+
pluginConfig: {
|
|
141
|
+
selection: {
|
|
142
|
+
enableDrag: true,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Custom Selection Rules
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const engine = new Engine({
|
|
152
|
+
plugins: [Selection],
|
|
153
|
+
pluginConfig: {
|
|
154
|
+
selection: {
|
|
155
|
+
rules: [
|
|
156
|
+
{
|
|
157
|
+
type: 'custom-node',
|
|
158
|
+
className: 'custom-node-wrapper',
|
|
159
|
+
idGetter: element => element.getAttribute('data-node-id') || '',
|
|
160
|
+
activeClassName: 'custom-node-selected',
|
|
161
|
+
onSelected: (context) => {
|
|
162
|
+
console.log('Custom node selected:', context.id)
|
|
163
|
+
return true // Return true to allow selection
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Programmatic Selection
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Select specific elements
|
|
176
|
+
engine.callTool('selection', 'select', [
|
|
177
|
+
{ type: 'node', id: 'node-1' },
|
|
178
|
+
{ type: 'node', id: 'node-2' },
|
|
179
|
+
])
|
|
180
|
+
|
|
181
|
+
// Deselect specific elements
|
|
182
|
+
engine.callTool('selection', 'deselect', [
|
|
183
|
+
{ type: 'node', id: 'node-1' },
|
|
184
|
+
])
|
|
185
|
+
|
|
186
|
+
// Get currently selected elements
|
|
187
|
+
const selected = engine.callTool('selection', 'getSelected')
|
|
188
|
+
console.log('Selected items:', selected)
|
|
189
|
+
|
|
190
|
+
// Clear all selections
|
|
191
|
+
engine.callTool('selection', 'clearSelection')
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Dynamic Rule Management
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Get plugin data
|
|
198
|
+
const selectionData = engine.getPluginData('selection')
|
|
199
|
+
|
|
200
|
+
// Register new rules
|
|
201
|
+
const unregister = selectionData.registerRules([
|
|
202
|
+
{
|
|
203
|
+
type: 'edge',
|
|
204
|
+
className: 'edge-wrapper',
|
|
205
|
+
idGetter: element => element.getAttribute('data-edge-id') || '',
|
|
206
|
+
activeClassName: 'edge-selected',
|
|
207
|
+
},
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
// Enable/disable rules
|
|
211
|
+
selectionData.setRuleEnabled('edge', false)
|
|
212
|
+
|
|
213
|
+
// Set overlap mode
|
|
214
|
+
selectionData.setElementOverlap('invert') // 'keep' | 'drop' | 'invert'
|
|
215
|
+
|
|
216
|
+
// Unregister rules
|
|
217
|
+
unregister()
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Listen to Selection Changes
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
class MyPlugin extends BasePlugin {
|
|
224
|
+
@inject.selection.selected()
|
|
225
|
+
selected!: SelectionSelectedItem[]
|
|
226
|
+
|
|
227
|
+
@subscribe.selection.selected()
|
|
228
|
+
onSelectedChange(selected: SelectionSelectedItem[]) {
|
|
229
|
+
console.log('Selection changed:', selected)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Integration with Canvas Plugin
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { Canvas } from '@knotx/plugins-canvas'
|
|
238
|
+
import { Selection } from '@knotx/plugins-selection'
|
|
239
|
+
|
|
240
|
+
const engine = new Engine({
|
|
241
|
+
plugins: [Canvas, Selection],
|
|
242
|
+
pluginConfig: {
|
|
243
|
+
canvas: {
|
|
244
|
+
minScale: 0.1,
|
|
245
|
+
maxScale: 3,
|
|
246
|
+
},
|
|
247
|
+
selection: {
|
|
248
|
+
enableDrag: true,
|
|
249
|
+
container: '.canvas-container', // Specify selection container
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Advanced Features
|
|
256
|
+
|
|
257
|
+
### Custom Selection Behavior
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
const engine = new Engine({
|
|
261
|
+
plugins: [Selection],
|
|
262
|
+
pluginConfig: {
|
|
263
|
+
selection: {
|
|
264
|
+
rules: [
|
|
265
|
+
{
|
|
266
|
+
type: 'node',
|
|
267
|
+
className: 'node-wrapper',
|
|
268
|
+
idGetter: element => element.getAttribute('data-node-id') || '',
|
|
269
|
+
onSelected: (context) => {
|
|
270
|
+
const { element, type, id, isDragging, getSelectedElements, select, deselect } = context
|
|
271
|
+
|
|
272
|
+
// Custom selection logic
|
|
273
|
+
if (isDragging) {
|
|
274
|
+
// Logic for drag selection
|
|
275
|
+
return true
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Logic for click selection
|
|
279
|
+
const selectedElements = getSelectedElements()
|
|
280
|
+
if (selectedElements.node && selectedElements.node.length > 0) {
|
|
281
|
+
// Already have selections, execute multi-select logic
|
|
282
|
+
return true
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return true
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Custom Selection Area Styling
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const engine = new Engine({
|
|
298
|
+
plugins: [Selection],
|
|
299
|
+
pluginConfig: {
|
|
300
|
+
selection: {
|
|
301
|
+
selectionAreaClassName: 'custom-selection-area',
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```css
|
|
308
|
+
.custom-selection-area {
|
|
309
|
+
background: rgba(74, 144, 226, 0.1);
|
|
310
|
+
border: 2px dashed #4A90E2;
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## File Directory Structure
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
packages/plugins-selection/
|
|
319
|
+
├── src/
|
|
320
|
+
│ ├── selection.tsx # Main implementation file
|
|
321
|
+
│ └── index.ts # Export file
|
|
322
|
+
├── dist/ # Build output directory
|
|
323
|
+
├── package.json # Package configuration
|
|
324
|
+
├── build.config.ts # Build configuration
|
|
325
|
+
├── tsconfig.json # TypeScript configuration
|
|
326
|
+
├── eslint.config.mjs # ESLint configuration
|
|
327
|
+
└── CHANGELOG.md # Changelog
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Core Files Description
|
|
331
|
+
|
|
332
|
+
- **selection.tsx**: Contains the main implementation of the Selection plugin, including selection area management, rule system, and event handling
|
|
333
|
+
- **index.ts**: Exports the Selection class and related type definitions
|
|
334
|
+
|
|
335
|
+
## Notes
|
|
336
|
+
|
|
337
|
+
1. **Performance Considerations**: With large numbers of elements, selection operations may impact performance; consider virtualization or pagination
|
|
338
|
+
2. **Event Conflicts**: May have event conflicts with other interaction plugins (like drag); pay attention to event priority
|
|
339
|
+
3. **Memory Management**: Clean up unnecessary selection rules promptly to avoid memory leaks
|
|
340
|
+
4. **Browser Compatibility**: Depends on modern browser DOM APIs; consider compatibility
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# @knotx/plugins-selection
|
|
2
|
+
|
|
3
|
+
选择插件,为 KnotX 提供元素选择功能。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/plugins-selection
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 概述
|
|
12
|
+
|
|
13
|
+
Selection 插件为 KnotX 提供了强大的元素选择功能,支持鼠标框选、键盘操作和程序化选择。该插件基于 `@knotx/viselect` 库实现,提供了灵活的选择规则和丰富的选择事件。
|
|
14
|
+
|
|
15
|
+
## 实现原理
|
|
16
|
+
|
|
17
|
+
Selection 插件的核心实现原理:
|
|
18
|
+
|
|
19
|
+
1. **选择区域管理**:使用 `@knotx/viselect` 库创建选择区域,支持拖拽选择
|
|
20
|
+
2. **规则系统**:通过规则系统定义不同类型元素的选择行为
|
|
21
|
+
3. **事件处理**:提供完整的选择事件生命周期管理
|
|
22
|
+
4. **状态同步**:与画布变换状态同步,确保选择区域的准确性
|
|
23
|
+
|
|
24
|
+
## 依赖关系
|
|
25
|
+
|
|
26
|
+
### 核心依赖
|
|
27
|
+
- `@knotx/core`:提供基础插件架构
|
|
28
|
+
- `@knotx/decorators`:提供装饰器支持
|
|
29
|
+
- `@knotx/viselect`:提供选择区域功能
|
|
30
|
+
|
|
31
|
+
### 插件依赖
|
|
32
|
+
- `@knotx/plugins-canvas`:获取画布变换状态和容器信息(可选)
|
|
33
|
+
|
|
34
|
+
## API 文档
|
|
35
|
+
|
|
36
|
+
### 主要类
|
|
37
|
+
|
|
38
|
+
#### Selection
|
|
39
|
+
|
|
40
|
+
选择插件的主要类,继承自 `BasePlugin`。
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
export class Selection extends BasePlugin<'selection', SelectionConfig> {
|
|
44
|
+
name = 'selection' as const
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 配置选项
|
|
49
|
+
|
|
50
|
+
#### SelectionConfig
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
export interface SelectionConfig {
|
|
54
|
+
/** 选择区域的类名 */
|
|
55
|
+
selectionAreaClassName?: string
|
|
56
|
+
/** 是否启用拖拽选择 */
|
|
57
|
+
enableDrag?: boolean
|
|
58
|
+
/** 选择规则 */
|
|
59
|
+
rules?: SelectionRule[]
|
|
60
|
+
/** 是否禁用默认规则 */
|
|
61
|
+
disableDefaultRules?: boolean
|
|
62
|
+
/** 选择容器 */
|
|
63
|
+
container?: string
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### SelectionRule
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
export interface SelectionRule {
|
|
71
|
+
/** 资源类型 */
|
|
72
|
+
type: string
|
|
73
|
+
/** 元素的类名 */
|
|
74
|
+
className: string
|
|
75
|
+
/** ID 获取函数 */
|
|
76
|
+
idGetter: (element: Element) => string
|
|
77
|
+
/** 激活状态的类名 */
|
|
78
|
+
activeClassName?: string
|
|
79
|
+
/** 选择回调函数 */
|
|
80
|
+
onSelected?: (context: SelectionContext) => boolean
|
|
81
|
+
/** 数据选择器类型 */
|
|
82
|
+
dataSelectorType?: string
|
|
83
|
+
/** 是否启用规则 */
|
|
84
|
+
enabled?: boolean
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 插件数据 (PluginData)
|
|
89
|
+
|
|
90
|
+
Selection 插件提供以下数据:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
interface PluginData {
|
|
94
|
+
selection: {
|
|
95
|
+
selected: SelectionSelectedItem[]
|
|
96
|
+
registerRules: (rules: SelectionRule[]) => () => void
|
|
97
|
+
setRuleEnabled: (type: string, enabled: boolean) => void
|
|
98
|
+
setClearSelectionBeforeStart: (isClearSelectionBeforeStart: boolean) => void
|
|
99
|
+
setElementOverlap: (overlap: OverlapMode) => void
|
|
100
|
+
resolveSelectables: () => void
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 插件工具 (PluginTools)
|
|
106
|
+
|
|
107
|
+
Selection 插件提供以下工具方法:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface PluginTools {
|
|
111
|
+
selection: {
|
|
112
|
+
select: (items: SelectionSelectedItem[]) => void
|
|
113
|
+
deselect: (items: SelectionSelectedItem[]) => void
|
|
114
|
+
getSelected: () => SelectionSelectedItem[]
|
|
115
|
+
clearSelection: () => void
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 类型定义
|
|
121
|
+
|
|
122
|
+
#### SelectionSelectedItem
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
export interface SelectionSelectedItem {
|
|
126
|
+
type: string
|
|
127
|
+
id: string
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 使用示例
|
|
132
|
+
|
|
133
|
+
### 基本用法
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { Selection } from '@knotx/plugins-selection'
|
|
137
|
+
|
|
138
|
+
const engine = new Engine({
|
|
139
|
+
plugins: [Selection],
|
|
140
|
+
pluginConfig: {
|
|
141
|
+
selection: {
|
|
142
|
+
enableDrag: true,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 自定义选择规则
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const engine = new Engine({
|
|
152
|
+
plugins: [Selection],
|
|
153
|
+
pluginConfig: {
|
|
154
|
+
selection: {
|
|
155
|
+
rules: [
|
|
156
|
+
{
|
|
157
|
+
type: 'custom-node',
|
|
158
|
+
className: 'custom-node-wrapper',
|
|
159
|
+
idGetter: element => element.getAttribute('data-node-id') || '',
|
|
160
|
+
activeClassName: 'custom-node-selected',
|
|
161
|
+
onSelected: (context) => {
|
|
162
|
+
console.log('Custom node selected:', context.id)
|
|
163
|
+
return true // 返回 true 表示允许选择
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 程序化选择
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// 选择特定元素
|
|
176
|
+
engine.callTool('selection', 'select', [
|
|
177
|
+
{ type: 'node', id: 'node-1' },
|
|
178
|
+
{ type: 'node', id: 'node-2' },
|
|
179
|
+
])
|
|
180
|
+
|
|
181
|
+
// 取消选择特定元素
|
|
182
|
+
engine.callTool('selection', 'deselect', [
|
|
183
|
+
{ type: 'node', id: 'node-1' },
|
|
184
|
+
])
|
|
185
|
+
|
|
186
|
+
// 获取当前选择的元素
|
|
187
|
+
const selected = engine.callTool('selection', 'getSelected')
|
|
188
|
+
console.log('Selected items:', selected)
|
|
189
|
+
|
|
190
|
+
// 清空所有选择
|
|
191
|
+
engine.callTool('selection', 'clearSelection')
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 动态管理选择规则
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// 获取插件数据
|
|
198
|
+
const selectionData = engine.getPluginData('selection')
|
|
199
|
+
|
|
200
|
+
// 注册新规则
|
|
201
|
+
const unregister = selectionData.registerRules([
|
|
202
|
+
{
|
|
203
|
+
type: 'edge',
|
|
204
|
+
className: 'edge-wrapper',
|
|
205
|
+
idGetter: element => element.getAttribute('data-edge-id') || '',
|
|
206
|
+
activeClassName: 'edge-selected',
|
|
207
|
+
},
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
// 启用/禁用规则
|
|
211
|
+
selectionData.setRuleEnabled('edge', false)
|
|
212
|
+
|
|
213
|
+
// 设置重叠模式
|
|
214
|
+
selectionData.setElementOverlap('invert') // 'keep' | 'drop' | 'invert'
|
|
215
|
+
|
|
216
|
+
// 取消注册规则
|
|
217
|
+
unregister()
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 监听选择变化
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
class MyPlugin extends BasePlugin {
|
|
224
|
+
@inject.selection.selected()
|
|
225
|
+
selected!: SelectionSelectedItem[]
|
|
226
|
+
|
|
227
|
+
@subscribe.selection.selected()
|
|
228
|
+
onSelectedChange(selected: SelectionSelectedItem[]) {
|
|
229
|
+
console.log('Selection changed:', selected)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 与 Canvas 插件集成
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { Canvas } from '@knotx/plugins-canvas'
|
|
238
|
+
import { Selection } from '@knotx/plugins-selection'
|
|
239
|
+
|
|
240
|
+
const engine = new Engine({
|
|
241
|
+
plugins: [Canvas, Selection],
|
|
242
|
+
pluginConfig: {
|
|
243
|
+
canvas: {
|
|
244
|
+
minScale: 0.1,
|
|
245
|
+
maxScale: 3,
|
|
246
|
+
},
|
|
247
|
+
selection: {
|
|
248
|
+
enableDrag: true,
|
|
249
|
+
container: '.canvas-container', // 指定选择容器
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## 高级功能
|
|
256
|
+
|
|
257
|
+
### 自定义选择行为
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
const engine = new Engine({
|
|
261
|
+
plugins: [Selection],
|
|
262
|
+
pluginConfig: {
|
|
263
|
+
selection: {
|
|
264
|
+
rules: [
|
|
265
|
+
{
|
|
266
|
+
type: 'node',
|
|
267
|
+
className: 'node-wrapper',
|
|
268
|
+
idGetter: element => element.getAttribute('data-node-id') || '',
|
|
269
|
+
onSelected: (context) => {
|
|
270
|
+
const { element, type, id, isDragging, getSelectedElements, select, deselect } = context
|
|
271
|
+
|
|
272
|
+
// 自定义选择逻辑
|
|
273
|
+
if (isDragging) {
|
|
274
|
+
// 拖拽选择时的逻辑
|
|
275
|
+
return true
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 单击选择时的逻辑
|
|
279
|
+
const selectedElements = getSelectedElements()
|
|
280
|
+
if (selectedElements.node && selectedElements.node.length > 0) {
|
|
281
|
+
// 已有选择,执行多选逻辑
|
|
282
|
+
return true
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return true
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 选择区域样式自定义
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const engine = new Engine({
|
|
298
|
+
plugins: [Selection],
|
|
299
|
+
pluginConfig: {
|
|
300
|
+
selection: {
|
|
301
|
+
selectionAreaClassName: 'custom-selection-area',
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```css
|
|
308
|
+
.custom-selection-area {
|
|
309
|
+
background: rgba(74, 144, 226, 0.1);
|
|
310
|
+
border: 2px dashed #4A90E2;
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## 文件目录结构
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
packages/plugins-selection/
|
|
319
|
+
├── src/
|
|
320
|
+
│ ├── selection.tsx # 主要实现文件
|
|
321
|
+
│ └── index.ts # 导出文件
|
|
322
|
+
├── dist/ # 构建输出目录
|
|
323
|
+
├── package.json # 包配置文件
|
|
324
|
+
├── build.config.ts # 构建配置
|
|
325
|
+
├── tsconfig.json # TypeScript 配置
|
|
326
|
+
├── eslint.config.mjs # ESLint 配置
|
|
327
|
+
└── CHANGELOG.md # 更新日志
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 核心文件说明
|
|
331
|
+
|
|
332
|
+
- **selection.tsx**:包含 Selection 插件的主要实现,包括选择区域管理、规则系统和事件处理
|
|
333
|
+
- **index.ts**:导出 Selection 类和相关类型定义
|
|
334
|
+
|
|
335
|
+
## 注意事项
|
|
336
|
+
|
|
337
|
+
1. **性能考虑**:大量元素时,选择操作可能影响性能,建议使用虚拟化或分页
|
|
338
|
+
2. **事件冲突**:与其他交互插件(如拖拽)可能存在事件冲突,注意事件优先级
|
|
339
|
+
3. **内存管理**:及时清理不需要的选择规则,避免内存泄漏
|
|
340
|
+
4. **浏览器兼容性**:依赖现代浏览器的 DOM API,注意兼容性
|
|
341
|
+
|
|
342
|
+
## 许可证
|
|
343
|
+
|
|
344
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knotx/plugins-selection",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Selection Plugin for Knotx",
|
|
5
5
|
"author": "boenfu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,19 +28,19 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@knotx/plugins-canvas": "0.4.
|
|
31
|
+
"@knotx/plugins-canvas": "0.4.13"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@knotx/viselect": "^3.9.0",
|
|
35
35
|
"rxjs": "^7.8.1",
|
|
36
|
-
"@knotx/core": "0.4.
|
|
37
|
-
"@knotx/decorators": "0.4.
|
|
36
|
+
"@knotx/core": "0.4.13",
|
|
37
|
+
"@knotx/decorators": "0.4.13"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@knotx/build-config": "0.4.
|
|
41
|
-
"@knotx/eslint-config": "0.4.
|
|
42
|
-
"@knotx/plugins-canvas": "0.4.
|
|
43
|
-
"@knotx/typescript-config": "0.4.
|
|
40
|
+
"@knotx/build-config": "0.4.13",
|
|
41
|
+
"@knotx/eslint-config": "0.4.13",
|
|
42
|
+
"@knotx/plugins-canvas": "0.4.13",
|
|
43
|
+
"@knotx/typescript-config": "0.4.13"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "unbuild",
|