@knotx/core 0.4.12 → 0.4.14
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 +738 -0
- package/README.md +738 -0
- package/package.json +6 -6
package/README.en.md
ADDED
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
# @knotx/core
|
|
2
|
+
|
|
3
|
+
**English** | [中文](./README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📦 Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @knotx/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
yarn add @knotx/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @knotx/core
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 📖 Overview
|
|
22
|
+
|
|
23
|
+
`@knotx/core` is the core package of the Knotx graph editor, providing the fundamental infrastructure needed to build visual graph editors. It includes engine management, plugin system, interaction management, element operations, layer rendering, and other core functionalities, offering developers powerful and flexible graph editing capabilities.
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Engine } from '@knotx/core'
|
|
29
|
+
|
|
30
|
+
// Create engine instance
|
|
31
|
+
const engine = new Engine({
|
|
32
|
+
container: { width: 800, height: 600, direction: 'horizontal' },
|
|
33
|
+
nodes: [
|
|
34
|
+
{ id: '1', position: { x: 100, y: 100 }, data: { label: 'Node 1' } },
|
|
35
|
+
{ id: '2', position: { x: 300, y: 200 }, data: { label: 'Node 2' } }
|
|
36
|
+
],
|
|
37
|
+
edges: [
|
|
38
|
+
{ id: 'e1', source: '1', target: '2', data: {} }
|
|
39
|
+
]
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Get nodes
|
|
43
|
+
const nodes = engine.getNodes()
|
|
44
|
+
console.log(nodes)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 📚 Complete API Documentation
|
|
48
|
+
|
|
49
|
+
### 🔧 Core Classes
|
|
50
|
+
|
|
51
|
+
#### Engine Class
|
|
52
|
+
|
|
53
|
+
The Engine is the core of Knotx, responsible for managing the entire graph editor's state and behavior.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Engine class type definition
|
|
57
|
+
interface Engine<TRenderType extends RenderType = RenderType, TNode extends IRecord = IRecord, TEdge extends IRecord = IRecord> {
|
|
58
|
+
// Engine methods and properties
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Properties:**
|
|
63
|
+
- `runtime: IEngineRuntime` - Runtime configuration
|
|
64
|
+
- `interaction: InteractionManager` - Interaction manager
|
|
65
|
+
- `nodesManager: DataManager<Node<TNode>>` - Node data manager
|
|
66
|
+
- `edgesManager: DataManager<Edge<TEdge>>` - Edge data manager
|
|
67
|
+
- `container: Container` - Container configuration
|
|
68
|
+
- `nodes: Node<TNode>[]` - Node array
|
|
69
|
+
- `edges: Edge<TEdge>[]` - Edge array
|
|
70
|
+
- `layers: Map<number, LayerComponent<TRenderType>[]>` - Layer component mapping
|
|
71
|
+
- `plugins: IPlugin[]` - Plugin array
|
|
72
|
+
|
|
73
|
+
**Methods:**
|
|
74
|
+
- `getNodes(): Node<TNode>[]` - Get all nodes
|
|
75
|
+
- `getEdges(): Edge<TEdge>[]` - Get all edges
|
|
76
|
+
- `getNode({ id }): Node<TNode> | undefined` - Get node by ID
|
|
77
|
+
- `getEdge({ id }): Edge<TEdge> | undefined` - Get edge by ID
|
|
78
|
+
- `getNodeDraft({ id }): Node<TNode> | undefined` - Get node draft
|
|
79
|
+
- `getEdgeDraft({ id }): Edge<TEdge> | undefined` - Get edge draft
|
|
80
|
+
- `getPlugin<TPlugin>({ pluginName }): TPlugin | undefined` - Get plugin
|
|
81
|
+
- `getNodeRenderer(type: string): NodeRenderType | undefined` - Get node renderer
|
|
82
|
+
- `getEdgeRenderer(type: string): EdgeRender | undefined` - Get edge renderer
|
|
83
|
+
- `getLayerComponents(layer: Layer): LayerComponent<TRenderType>[]` - Get layer components
|
|
84
|
+
- `addNodePipe(pipe: DataOperationPipe<Node<TNode>>)` - Add node operation pipe
|
|
85
|
+
- `addEdgePipe(pipe: DataOperationPipe<Edge<TEdge>>)` - Add edge operation pipe
|
|
86
|
+
- `dispatchNodeOperation(operation: DataOperation<Node<TNode>>)` - Dispatch node operation
|
|
87
|
+
- `dispatchEdgeOperation(operation: DataOperation<Edge<TEdge>>)` - Dispatch edge operation
|
|
88
|
+
- `registerNodeRenderer(type: string, renderer: NodeRenderType): () => void` - Register node renderer
|
|
89
|
+
- `registerEdgeRenderer(type: string, renderer: EdgeRenderType, config: Required<EdgeConfig>): () => void` - Register edge renderer
|
|
90
|
+
- `registerPluginData<T, TP>(pluginName: T, property: TP, data: BehaviorSubject<PluginData[T][TP]>): void` - Register plugin data
|
|
91
|
+
- `subscribePluginData<T, TP>(pluginName: T, property: TP, observer: (value: PluginData[T][TP]) => void): Subscription | null` - Subscribe to plugin data
|
|
92
|
+
- `registerPluginTool<T, TP>(pluginName: T, property: TP, data: { description: string; parameters: Schema; func: PluginTools[T][TP] }): void` - Register plugin tool
|
|
93
|
+
- `resetPluginData<T>(pluginName: T): void` - Reset plugin data
|
|
94
|
+
- `resetPluginTool<T>(pluginName: T): void` - Reset plugin tool
|
|
95
|
+
- `changePluginConfig({ pluginName, config }): void` - Change plugin configuration
|
|
96
|
+
- `callTool: CallToolMethod` - Call tool method
|
|
97
|
+
- `listPlugins(): IPluginInfo[]` - List all plugins
|
|
98
|
+
- `listPluginTools({ pluginName }): IToolInfo[]` - List plugin tools
|
|
99
|
+
- `listEngineTools(): IToolInfo[]` - List engine tools
|
|
100
|
+
- `destroy()` - Destroy engine
|
|
101
|
+
|
|
102
|
+
#### BasePlugin Class
|
|
103
|
+
|
|
104
|
+
Base class for plugins, providing fundamental functionality for plugin development.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// BasePlugin abstract class type definition
|
|
108
|
+
abstract class BasePlugin<TPluginName extends string = string, TPluginConfig extends IRecord | undefined = undefined, TRenderType extends RenderType = RenderType> {
|
|
109
|
+
// Plugin abstract methods and properties
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Properties:**
|
|
114
|
+
- `abstract name: TPluginName` - Plugin name
|
|
115
|
+
- `pluginId: string` - Plugin unique ID
|
|
116
|
+
- `protected subscriptions: (SubscriptionLike | (() => void))[]` - Subscription collection
|
|
117
|
+
- `protected callTool: Engine['callTool']` - Call tool method
|
|
118
|
+
|
|
119
|
+
**Methods:**
|
|
120
|
+
- `onInit?(config: TPluginConfig): void` - Initialization callback
|
|
121
|
+
- `onConfigChange?(config: TPluginConfig): void` - Configuration change callback
|
|
122
|
+
- `onDestroy?(): void` - Destroy callback
|
|
123
|
+
|
|
124
|
+
#### InteractionManager Class
|
|
125
|
+
|
|
126
|
+
Interaction manager responsible for managing user interaction priorities and states.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// InteractionManager class type definition
|
|
130
|
+
class InteractionManager {
|
|
131
|
+
// Interaction manager methods and properties
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Properties:**
|
|
136
|
+
- `active: Interaction | undefined` - Current active interaction
|
|
137
|
+
|
|
138
|
+
**Methods:**
|
|
139
|
+
- `canInteract(priority: InteractionPriority): boolean` - Check if can interact
|
|
140
|
+
- `start(pluginId: string, type: string, priority: InteractionPriority): () => void` - Start interaction
|
|
141
|
+
- `end(pluginId: string, type: string): void` - End interaction
|
|
142
|
+
|
|
143
|
+
#### Runtime Class
|
|
144
|
+
|
|
145
|
+
Runtime manager handling context execution and value processing.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Runtime class type definition
|
|
149
|
+
class Runtime {
|
|
150
|
+
// Runtime methods and properties
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Properties:**
|
|
155
|
+
- `currentContext: { type: any; value: any } | undefined` - Current context
|
|
156
|
+
|
|
157
|
+
**Methods:**
|
|
158
|
+
- `runInContext<T>(type: any, handler: () => T, contextValue?: any): T` - Run in context
|
|
159
|
+
- `getValue<T>(engine: Engine<any>, options: { paths: any[]; matcher?: (engine: Engine<any>) => BehaviorSubject<any>; selector?: (value: T, context?: any) => any }): any` - Get value
|
|
160
|
+
- `static getInstance(): Runtime` - Get singleton instance
|
|
161
|
+
- `static DEFAULT_VALUE_HANDLER: <T>(value: BehaviorSubject<T> | T, options: { paths: string[]; selector?: (value: T, context?: any) => any; context?: any }) => T` - Default value handler
|
|
162
|
+
|
|
163
|
+
#### DataManager Class
|
|
164
|
+
|
|
165
|
+
Data manager for managing CRUD operations and version control.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// DataManager class type definition
|
|
169
|
+
class DataManager<TData extends IData = IData, TTag extends string = any> {
|
|
170
|
+
// Data manager methods and properties
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Properties:**
|
|
175
|
+
- `readonly tag: TTag` - Tag
|
|
176
|
+
- `readonly dataMap$: BehaviorSubject<Map<string, TData>>` - Data mapping
|
|
177
|
+
- `readonly patchVersion$: BehaviorSubject<number>` - Patch version
|
|
178
|
+
- `readonly mapVersion$: BehaviorSubject<number>` - Map version
|
|
179
|
+
- `version: number` - Version number
|
|
180
|
+
|
|
181
|
+
**Methods:**
|
|
182
|
+
- `init(initialDataList: TData[]): void` - Initialize
|
|
183
|
+
- `getDataList$(): Observable<TData[]>` - Get data list stream
|
|
184
|
+
- `getDataList(): TData[]` - Get data list
|
|
185
|
+
- `getData(id: string): TData | undefined` - Get data
|
|
186
|
+
- `getOperations$(): Observable<DataOperation<TData>>` - Get operations stream
|
|
187
|
+
- `dispatch(operation: DataOperation<TData>): void` - Dispatch operation
|
|
188
|
+
- `getDraftDataList(draftId: string): TData[] | undefined` - Get draft data list
|
|
189
|
+
|
|
190
|
+
#### DualRelation Class
|
|
191
|
+
|
|
192
|
+
Dual relation manager for managing parent-child relationships.
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// DualRelation class type definition
|
|
196
|
+
class DualRelation<P, C> {
|
|
197
|
+
// Dual relation manager methods and properties
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Properties:**
|
|
202
|
+
- `version: BehaviorSubject<number>` - Version number
|
|
203
|
+
|
|
204
|
+
**Methods:**
|
|
205
|
+
- `addRelation(parent: P, child: C): void` - Add relation
|
|
206
|
+
- `removeRelation(parent: P, child: C): void` - Remove relation
|
|
207
|
+
- `getChildren(parent: P): C[]` - Get children
|
|
208
|
+
- `getParent(child: C): P | undefined` - Get parent
|
|
209
|
+
- `clear(): void` - Clear relations
|
|
210
|
+
|
|
211
|
+
#### Element Interface and DOMElement Class
|
|
212
|
+
|
|
213
|
+
Element abstraction providing cross-platform element operation interfaces.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
interface Element {
|
|
217
|
+
classList: ElementClassList
|
|
218
|
+
attribute: ElementAttribute
|
|
219
|
+
uniqSelector: string | undefined
|
|
220
|
+
getRect: () => ElementRect
|
|
221
|
+
addEventListener: EventListenerDefinition
|
|
222
|
+
removeEventListener: EventListenerDefinition
|
|
223
|
+
query: (selector: string) => Element | null
|
|
224
|
+
queryAll: (selector: string) => Element[]
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
class DOMElement implements Element {
|
|
228
|
+
constructor(readonly dom: HTMLElement) {}
|
|
229
|
+
static fromDOM(dom: HTMLElement): DOMElement
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 🎭 Type Definitions
|
|
234
|
+
|
|
235
|
+
#### Basic Types
|
|
236
|
+
```typescript
|
|
237
|
+
type HorizontalAlignment = 'left' | 'right'
|
|
238
|
+
type VerticalAlignment = 'top' | 'bottom'
|
|
239
|
+
type Direction = 'horizontal' | 'vertical'
|
|
240
|
+
type IRecord = Record<string, any>
|
|
241
|
+
type Position = VerticalAlignment | HorizontalAlignment | `${HorizontalAlignment}-${VerticalAlignment}` | 'center'
|
|
242
|
+
type RenderType = (...args: any[]) => any
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Node Related Types
|
|
246
|
+
```typescript
|
|
247
|
+
interface NodePosition {
|
|
248
|
+
x: number
|
|
249
|
+
y: number
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
interface NodeMeasured {
|
|
253
|
+
width: number
|
|
254
|
+
height: number
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
interface Node<TData extends IRecord = IRecord> {
|
|
258
|
+
id: string
|
|
259
|
+
type?: string
|
|
260
|
+
position: NodePosition
|
|
261
|
+
measured?: NodeMeasured
|
|
262
|
+
data: TData
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
interface NodeProps<TData extends IRecord = IRecord> {
|
|
266
|
+
node: Node<TData>
|
|
267
|
+
renderVersion?: number
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
type NodeRenderType<TD extends IRecord = any, TR = any> = (props: NodeProps<TD>) => TR
|
|
271
|
+
type NodeOperation<T extends IRecord = any> = DataOperation<Node<T>>
|
|
272
|
+
type NodeOperationPipe<T extends IRecord = any> = DataOperationPipe<Node<T>>
|
|
273
|
+
type NodeOperatorFunction<T extends IRecord = any, TArgs extends any[] = any[]> = (...args: TArgs) => NodeOperation<T>[]
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Edge Related Types
|
|
277
|
+
```typescript
|
|
278
|
+
interface EdgeConfig {
|
|
279
|
+
sourcePosition?: Position
|
|
280
|
+
targetPosition?: Position
|
|
281
|
+
sourceYOffset?: string | number
|
|
282
|
+
sourceXOffset?: string | number
|
|
283
|
+
targetYOffset?: string | number
|
|
284
|
+
targetXOffset?: string | number
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
interface Edge<TData extends IRecord = IRecord> extends EdgeConfig {
|
|
288
|
+
id: string
|
|
289
|
+
source: string
|
|
290
|
+
target: string
|
|
291
|
+
type?: string
|
|
292
|
+
data?: TData
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
interface EdgeProps<TData extends IRecord = IRecord> {
|
|
296
|
+
edge: Edge<TData>
|
|
297
|
+
sourceX: number
|
|
298
|
+
sourceY: number
|
|
299
|
+
targetX: number
|
|
300
|
+
targetY: number
|
|
301
|
+
renderVersion?: number
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
type EdgeRenderType<TD extends IRecord = any, TR = any> = (props: EdgeProps<TD>) => TR
|
|
305
|
+
|
|
306
|
+
interface EdgeRender<TD extends IRecord = any, TR = any> {
|
|
307
|
+
renderer: EdgeRenderType<TD, TR>
|
|
308
|
+
config: Required<EdgeConfig>
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
type EdgeOperation<T extends IRecord = any> = DataOperation<Edge<T>>
|
|
312
|
+
type EdgeOperationPipe<T extends IRecord = any> = DataOperationPipe<Edge<T>>
|
|
313
|
+
type EdgeOperatorFunction<T extends IRecord = any, TArgs extends any[] = any[]> = (...args: TArgs) => EdgeOperation<T>[]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### Container Types
|
|
317
|
+
```typescript
|
|
318
|
+
interface Container {
|
|
319
|
+
width: number
|
|
320
|
+
height: number
|
|
321
|
+
direction: Direction
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### Layer Types
|
|
326
|
+
```typescript
|
|
327
|
+
enum Layer {
|
|
328
|
+
Canvas = 0,
|
|
329
|
+
Background = 4,
|
|
330
|
+
Edges = 16,
|
|
331
|
+
Nodes = 64,
|
|
332
|
+
Foreground = 256,
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface LayerComponent<TRenderType> {
|
|
336
|
+
plugin: string
|
|
337
|
+
name: string
|
|
338
|
+
layer: Layer
|
|
339
|
+
render: TRenderType
|
|
340
|
+
offset?: number
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
#### Plugin Types
|
|
345
|
+
```typescript
|
|
346
|
+
interface IPlugin<TPluginName extends string = string, TPluginConfig extends IRecord | undefined = any> {
|
|
347
|
+
name: TPluginName
|
|
348
|
+
pluginId: string
|
|
349
|
+
description?: string
|
|
350
|
+
onInit?: (config: TPluginConfig) => void
|
|
351
|
+
onConfigChange?: (config: TPluginConfig) => void
|
|
352
|
+
onDestroy?: () => void
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
type Plugin<TName extends string = string, TConfig extends IRecord | undefined = any, TRenderType extends RenderType = RenderType> = new (__: TConfig) => BasePlugin<TName, TConfig, TRenderType>
|
|
356
|
+
|
|
357
|
+
interface PluginData {} // Module augmentation interface
|
|
358
|
+
interface PluginTools {} // Module augmentation interface
|
|
359
|
+
interface EngineTools {} // Module augmentation interface
|
|
360
|
+
|
|
361
|
+
interface IPluginInfo {
|
|
362
|
+
name: string
|
|
363
|
+
description?: string
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
interface IToolInfo {
|
|
367
|
+
type: 'function'
|
|
368
|
+
name: string
|
|
369
|
+
description: string
|
|
370
|
+
parameters: Schema
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### Data Operation Types
|
|
375
|
+
```typescript
|
|
376
|
+
interface IData {
|
|
377
|
+
id: string
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
interface DataAddOperation<T extends IData = IData> {
|
|
381
|
+
type: 'add'
|
|
382
|
+
data: T
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
interface DataRemoveOperation<_T extends IData = IData> {
|
|
386
|
+
type: 'remove'
|
|
387
|
+
id: string
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
interface DataUpdateOperation<T extends IData = IData> {
|
|
391
|
+
type: 'update'
|
|
392
|
+
id: string
|
|
393
|
+
data: T
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
interface DataBatchOperation<T extends IData = IData> {
|
|
397
|
+
type: 'batch'
|
|
398
|
+
operations: DataOperation<T>[]
|
|
399
|
+
isInit?: boolean
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
interface DataStartDraftOperation<T extends IData = IData> {
|
|
403
|
+
type: 'startDraft'
|
|
404
|
+
draftId: string
|
|
405
|
+
data: T
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
interface DataCommitDraftOperation<T extends IData = IData> {
|
|
409
|
+
type: 'commitDraft'
|
|
410
|
+
draftId: string
|
|
411
|
+
data: T
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
interface DataDiscardDraftOperation<T extends IData = IData> {
|
|
415
|
+
type: 'discardDraft'
|
|
416
|
+
draftId: string
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
interface DataDraftOperation<T extends IData = IData> {
|
|
420
|
+
type: 'draft'
|
|
421
|
+
draftId: string
|
|
422
|
+
operation: DataOperation<T>
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
type DataOperation<T extends IData = IData> = DataAddOperation<T> | DataRemoveOperation<T> | DataUpdateOperation<T> | DataBatchOperation<T> | DataStartDraftOperation<T> | DataCommitDraftOperation<T> | DataDiscardDraftOperation<T> | DataDraftOperation<T>
|
|
426
|
+
|
|
427
|
+
interface DataOperationPipe<T extends IData = IData> {
|
|
428
|
+
transform?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
|
|
429
|
+
preOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
|
|
430
|
+
postOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<{ dataMap: Map<string, T>, operations: DataOperation<T>[] }, { dataMap: Map<string, T>, operations: DataOperation<T>[] }>
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### Interaction Types
|
|
435
|
+
```typescript
|
|
436
|
+
enum InteractionPriority {
|
|
437
|
+
InputActive = 2000,
|
|
438
|
+
EntityConnectDrag = 1930,
|
|
439
|
+
EntityMeasureDrag = 1920,
|
|
440
|
+
EntityPositionDrag = 1910,
|
|
441
|
+
ContinuousDrag = 1900,
|
|
442
|
+
ContextMenu = 1800,
|
|
443
|
+
KeyboardShortcut = 1700,
|
|
444
|
+
ClickSelection = 1600,
|
|
445
|
+
DoubleClickEdit = 1500,
|
|
446
|
+
MarqueeSelection = 1300,
|
|
447
|
+
LassoSelection = 1250,
|
|
448
|
+
LongPress = 1100,
|
|
449
|
+
HoverTooltip = 1000,
|
|
450
|
+
CanvasPan = 900,
|
|
451
|
+
CanvasZoom = 800,
|
|
452
|
+
CanvasContextMenu = 700,
|
|
453
|
+
CanvasClick = 600,
|
|
454
|
+
MultiTouchGesture = 500,
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
interface Interaction {
|
|
458
|
+
pluginId: string
|
|
459
|
+
type: string
|
|
460
|
+
priority: InteractionPriority
|
|
461
|
+
active?: boolean
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
#### Element Types
|
|
466
|
+
```typescript
|
|
467
|
+
interface ElementClassList {
|
|
468
|
+
toString: () => string
|
|
469
|
+
add: (...tokens: string[]) => void
|
|
470
|
+
contains: (token: string) => boolean
|
|
471
|
+
remove: (...tokens: string[]) => void
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
interface ElementAttribute {
|
|
475
|
+
get: (name: string) => string | null
|
|
476
|
+
set: (name: string, value: string) => void
|
|
477
|
+
remove: (name: string) => void
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
interface ElementRect {
|
|
481
|
+
height: number
|
|
482
|
+
width: number
|
|
483
|
+
x: number
|
|
484
|
+
y: number
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
interface EventListenerDefinition<E = any> {
|
|
488
|
+
(type: string, listener: ((evt: E) => void) | EventListenerObject<E>, options?: boolean | AddEventListenerOptions): void
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
#### Engine Types
|
|
493
|
+
```typescript
|
|
494
|
+
interface EngineOptions<TNode extends IRecord = IRecord, TEdge extends IRecord = IRecord> {
|
|
495
|
+
container: Container
|
|
496
|
+
plugins?: Plugin[]
|
|
497
|
+
pluginConfig?: IRecord
|
|
498
|
+
nodes?: Node<TNode>[]
|
|
499
|
+
edges?: Edge<TEdge>[]
|
|
500
|
+
runtime?: IEngineRuntime
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
interface IEngineRuntime {
|
|
504
|
+
render?: {
|
|
505
|
+
getValue: <T, R = T>(value: BehaviorSubject<T> | T, options: {
|
|
506
|
+
paths: string[]
|
|
507
|
+
selector?: (value: T, context?: any) => R
|
|
508
|
+
context?: any
|
|
509
|
+
}) => T | R
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
interface CallToolMethod {
|
|
514
|
+
<T extends keyof PluginTools, TP extends keyof PluginTools[T]>(pluginName: Extract<T, keyof PluginTools>, toolName: Extract<TP, keyof PluginTools[T]>, ...args: Parameters<PluginTools[T][TP]>): ReturnType<PluginTools[T][TP]>
|
|
515
|
+
<T extends keyof EngineTools>(engineToolName: Extract<T, keyof EngineTools>, ...args: Parameters<EngineTools[T]>): ReturnType<EngineTools[T]>
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### 🛠️ Utility Functions
|
|
520
|
+
|
|
521
|
+
#### Hook Functions
|
|
522
|
+
```typescript
|
|
523
|
+
function use<T>(hook: () => T): T
|
|
524
|
+
function use<T, TContext>(hook: () => { __contextRef__: T, __contextValue__: TContext }, context: TContext): T
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Layer Functions
|
|
528
|
+
```typescript
|
|
529
|
+
function getLayerRenders<TRenderType extends RenderType = RenderType>(plugin: IPlugin): LayerComponent<TRenderType>[]
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### Utility Functions (from @knotx/utils)
|
|
533
|
+
```typescript
|
|
534
|
+
// BEM class name utilities
|
|
535
|
+
function bem(block: string, element?: string, modifier?: string, prefix?: string): string
|
|
536
|
+
function addBemModifier(className: string, modifier: string): string
|
|
537
|
+
|
|
538
|
+
// Unique ID generation
|
|
539
|
+
function generateId(): string
|
|
540
|
+
|
|
541
|
+
// Symbol utilities
|
|
542
|
+
function getSymbol<TName extends string>(name: TName): symbol & { __knotx__?: TName }
|
|
543
|
+
|
|
544
|
+
// Data operation utilities
|
|
545
|
+
function isInitOperation<T extends IData>(operation: DataOperation<T>): operation is DataInitBatchOperation<T>
|
|
546
|
+
function isDraftOperation<T extends IData>(operation: DataOperation<T>): operation is Extract<DataOperation<T>, { draftId: string }>
|
|
547
|
+
function isEmptyBatchOperation<T extends IData>(operation: DataOperation<T>): operation is DataEmptyBatchOperation<T>
|
|
548
|
+
function flattenOperations<T extends IData>(operations: DataOperation<T>[]): DataOperation<T>[]
|
|
549
|
+
function emptyOperation<T extends IData>(): DataEmptyBatchOperation<T>
|
|
550
|
+
function buildDiffOperation<T extends IData>(previousDataMap: Map<string, T>, dataMap: Map<string, T>, compare?: (a: T | undefined, b: T | undefined) => boolean): DataBatchOperation<T>
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### 📘 Usage Examples
|
|
554
|
+
|
|
555
|
+
#### Basic Usage
|
|
556
|
+
```typescript
|
|
557
|
+
import { Engine } from '@knotx/core'
|
|
558
|
+
|
|
559
|
+
// Create engine
|
|
560
|
+
const engine = new Engine({
|
|
561
|
+
container: { width: 800, height: 600, direction: 'horizontal' },
|
|
562
|
+
nodes: [
|
|
563
|
+
{ id: '1', position: { x: 100, y: 100 }, data: { label: 'Node 1' } }
|
|
564
|
+
],
|
|
565
|
+
edges: []
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
// Get data
|
|
569
|
+
const nodes = engine.getNodes()
|
|
570
|
+
const node = engine.getNode({ id: '1' })
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
#### Plugin Development
|
|
574
|
+
```typescript
|
|
575
|
+
import { BasePlugin, Layer } from '@knotx/core'
|
|
576
|
+
|
|
577
|
+
class MyPlugin extends BasePlugin<'my-plugin', { theme: string }> {
|
|
578
|
+
name = 'my-plugin' as const
|
|
579
|
+
|
|
580
|
+
onInit(config: { theme: string }) {
|
|
581
|
+
// Plugin initialization logic
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Data Operations
|
|
587
|
+
```typescript
|
|
588
|
+
import { DataManager } from '@knotx/core'
|
|
589
|
+
|
|
590
|
+
const dataManager = new DataManager<Node>('nodes')
|
|
591
|
+
dataManager.init([
|
|
592
|
+
{ id: '1', position: { x: 0, y: 0 }, data: {} }
|
|
593
|
+
])
|
|
594
|
+
|
|
595
|
+
// Add data
|
|
596
|
+
dataManager.dispatch({
|
|
597
|
+
type: 'add',
|
|
598
|
+
data: { id: '2', position: { x: 100, y: 100 }, data: {} }
|
|
599
|
+
})
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
#### Interaction Management
|
|
603
|
+
```typescript
|
|
604
|
+
import { InteractionManager, InteractionPriority } from '@knotx/core'
|
|
605
|
+
|
|
606
|
+
const interaction = new InteractionManager()
|
|
607
|
+
const cancel = interaction.start('plugin-id', 'drag', InteractionPriority.EntityPositionDrag)
|
|
608
|
+
|
|
609
|
+
// Check if can interact
|
|
610
|
+
if (interaction.canInteract(InteractionPriority.ClickSelection)) {
|
|
611
|
+
// Execute interaction logic
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Cancel interaction
|
|
615
|
+
cancel()
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
## 🗂️ File Directory Structure
|
|
619
|
+
|
|
620
|
+
```
|
|
621
|
+
packages/core/
|
|
622
|
+
├── src/
|
|
623
|
+
│ ├── index.ts # Main export file
|
|
624
|
+
│ ├── definition.ts # Type definitions and interfaces
|
|
625
|
+
│ ├── engine.ts # Core engine implementation
|
|
626
|
+
│ ├── element.ts # Element abstraction layer
|
|
627
|
+
│ ├── plugin.ts # Plugin base class
|
|
628
|
+
│ ├── interaction.ts # Interaction manager
|
|
629
|
+
│ ├── runtime.ts # Runtime management
|
|
630
|
+
│ ├── layer.tsx # Layer rendering
|
|
631
|
+
│ ├── use.ts # Hook functions
|
|
632
|
+
│ ├── data.ts # Data management (re-export)
|
|
633
|
+
│ └── utils.ts # Utility functions (re-export)
|
|
634
|
+
├── dist/ # Build output directory
|
|
635
|
+
├── package.json # Package configuration
|
|
636
|
+
├── tsconfig.json # TypeScript configuration
|
|
637
|
+
├── build.config.ts # Build configuration
|
|
638
|
+
└── README.md # Project documentation
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
## 🔧 Advanced Usage
|
|
642
|
+
|
|
643
|
+
### Custom Plugin Development
|
|
644
|
+
|
|
645
|
+
```typescript
|
|
646
|
+
import type { LayerComponent } from '@knotx/core'
|
|
647
|
+
|
|
648
|
+
import { BasePlugin, Layer } from '@knotx/core'
|
|
649
|
+
|
|
650
|
+
class CustomPlugin extends BasePlugin<'custom', { theme: string }> {
|
|
651
|
+
name = 'custom' as const
|
|
652
|
+
|
|
653
|
+
// Declare plugin data
|
|
654
|
+
declare pluginData: {
|
|
655
|
+
selectedNodes: string[]
|
|
656
|
+
highlightColor: string
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Declare plugin tools
|
|
660
|
+
declare pluginTools: {
|
|
661
|
+
selectNode: (nodeId: string) => void
|
|
662
|
+
clearSelection: () => void
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
onInit(config: { theme: string }) {
|
|
666
|
+
// Register plugin data
|
|
667
|
+
this.engine.registerPluginData('custom', 'selectedNodes', new BehaviorSubject([]))
|
|
668
|
+
this.engine.registerPluginData('custom', 'highlightColor', new BehaviorSubject('#blue'))
|
|
669
|
+
|
|
670
|
+
// Register plugin tools
|
|
671
|
+
this.engine.registerPluginTool('custom', 'selectNode', {
|
|
672
|
+
description: 'Select node',
|
|
673
|
+
parameters: { type: 'string' },
|
|
674
|
+
func: (nodeId: string) => {
|
|
675
|
+
// Implement selection logic
|
|
676
|
+
console.log('Selecting node:', nodeId)
|
|
677
|
+
}
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
// Register layer component
|
|
681
|
+
this.engine.registerLayerComponent({
|
|
682
|
+
plugin: this.name,
|
|
683
|
+
name: 'selection-layer',
|
|
684
|
+
layer: Layer.Foreground,
|
|
685
|
+
render: this.renderSelection.bind(this)
|
|
686
|
+
})
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
renderSelection() {
|
|
690
|
+
return '<div class="selection-overlay">Selection Layer</div>'
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Data Operation Pipes
|
|
696
|
+
|
|
697
|
+
```typescript
|
|
698
|
+
import type { EdgeOperation, NodeOperation } from '@knotx/core'
|
|
699
|
+
|
|
700
|
+
// Node operation pipe
|
|
701
|
+
engine.addNodePipe((operations: NodeOperation[]) => {
|
|
702
|
+
return operations.map((op) => {
|
|
703
|
+
if (op.type === 'update') {
|
|
704
|
+
// Validate data before update
|
|
705
|
+
if (!validateNodeData(op.data)) {
|
|
706
|
+
throw new Error('Invalid node data')
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return op
|
|
710
|
+
})
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
// Edge operation pipe
|
|
714
|
+
engine.addEdgePipe((operations: EdgeOperation[]) => {
|
|
715
|
+
return operations.filter((op) => {
|
|
716
|
+
// Filter invalid edge operations
|
|
717
|
+
return op.source !== op.target
|
|
718
|
+
})
|
|
719
|
+
})
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## 📄 License
|
|
725
|
+
|
|
726
|
+
This project is licensed under the [MIT License](../../LICENSE).
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
## 🔗 Related Links
|
|
731
|
+
|
|
732
|
+
- [Homepage](https://github.com/boenfu/knotx)
|
|
733
|
+
- [Issues](https://github.com/boenfu/knotx/issues)
|
|
734
|
+
- [Contributing Guide](../../CONTRIBUTING.md)
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
Made with ❤️ by the Knotx team
|