0
# Canvas Operations
1
2
Interactive canvas functionality for visual workflow editing with drag-and-drop node placement, connection management, and canvas navigation.
3
4
## Capabilities
5
6
### Canvas Component
7
8
Main canvas component providing the visual workflow editor interface.
9
10
```typescript { .api }
11
/**
12
* Canvas component props for workflow editor
13
*/
14
interface CanvasProps {
15
id?: string;
16
nodes: CanvasNode[];
17
connections: CanvasConnection[];
18
controlsPosition?: PanelPosition;
19
eventBus?: EventBus<CanvasEventBusEvents>;
20
readOnly?: boolean;
21
executing?: boolean;
22
keyBindings?: boolean;
23
loading?: boolean;
24
}
25
26
/**
27
* Canvas component events
28
*/
29
interface CanvasEvents {
30
'update:modelValue': (elements: CanvasElement[]) => void;
31
'update:node:position': (id: string, position: XYPosition) => void;
32
'click:node': (id: string, event: MouseEvent) => void;
33
'create:node': (nodeType: string, position: XYPosition) => void;
34
'delete:node': (id: string) => void;
35
'run:workflow': () => void;
36
'save:workflow': () => void;
37
}
38
39
type PanelPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
40
```
41
42
### Canvas Node Data
43
44
Data structure representing nodes on the canvas.
45
46
```typescript { .api }
47
interface CanvasNodeData {
48
id: string;
49
name: string;
50
subtitle: string;
51
type: string;
52
typeVersion: number;
53
disabled: boolean;
54
inputs: CanvasConnectionPort[];
55
outputs: CanvasConnectionPort[];
56
connections: {
57
[CanvasConnectionMode.Input]: INodeConnections;
58
[CanvasConnectionMode.Output]: INodeConnections;
59
};
60
issues: {
61
items: string[];
62
visible: boolean;
63
};
64
pinnedData: {
65
count: number;
66
visible: boolean;
67
};
68
execution: {
69
status?: ExecutionStatus;
70
waiting?: string;
71
running: boolean;
72
};
73
runData: {
74
outputMap?: ExecutionOutputMap;
75
iterations: number;
76
visible: boolean;
77
};
78
render: CanvasNodeRender;
79
}
80
81
interface CanvasConnectionPort {
82
node?: string;
83
type: NodeConnectionType;
84
index: number;
85
required?: boolean;
86
maxConnections?: number;
87
label?: string;
88
}
89
90
interface CanvasNodeRender {
91
type: CanvasNodeRenderType;
92
options: CanvasNodeRenderOptions;
93
}
94
95
enum CanvasConnectionMode {
96
Input = 'inputs',
97
Output = 'outputs'
98
}
99
100
type NodeConnectionType = 'main' | 'ai_memory' | 'ai_document' | 'ai_tool' | 'ai_languageModel' | 'ai_embedding' | 'ai_vectorStore' | 'ai_textSplitter' | 'ai_outputParser';
101
```
102
103
### Canvas Operations Composable
104
105
Composable providing canvas manipulation functions.
106
107
```typescript { .api }
108
/**
109
* Composable for canvas operations
110
*/
111
function useCanvasOperations(): {
112
addNodes(nodes: AddedNode[], connections?: AddedNodeConnection[]): void;
113
deleteNode(id: string): void;
114
copyNodes(ids: string[]): void;
115
cutNodes(ids: string[]): void;
116
pasteNodes(position?: XYPosition): void;
117
selectAllNodes(): void;
118
deselectAllNodes(): void;
119
revertDeleteNode(id: string): void;
120
setNodeSelected(id: string, selected?: boolean): void;
121
updateNodePosition(id: string, position: XYPosition): void;
122
createConnection(source: CanvasConnectionPort, target: CanvasConnectionPort): void;
123
deleteConnection(connection: CanvasConnection): void;
124
};
125
126
interface AddedNode {
127
type: string;
128
openDetail?: boolean;
129
isAutoAdd?: boolean;
130
actionName?: string;
131
position?: XYPosition;
132
name?: string;
133
}
134
135
interface AddedNodeConnection {
136
from: {
137
nodeIndex: number;
138
outputIndex?: number;
139
type?: NodeConnectionType;
140
};
141
to: {
142
nodeIndex: number;
143
inputIndex?: number;
144
type?: NodeConnectionType;
145
};
146
}
147
```
148
149
**Usage Example:**
150
151
```typescript
152
import { useCanvasOperations } from '@/composables/useCanvasOperations';
153
154
const canvasOperations = useCanvasOperations();
155
156
// Add multiple nodes with connections
157
canvasOperations.addNodes([
158
{
159
type: 'n8n-nodes-base.httpRequest',
160
position: [100, 100],
161
name: 'Fetch Data'
162
},
163
{
164
type: 'n8n-nodes-base.set',
165
position: [300, 100],
166
name: 'Process Data'
167
}
168
], [
169
{
170
from: { nodeIndex: 0, outputIndex: 0 },
171
to: { nodeIndex: 1, inputIndex: 0 }
172
}
173
]);
174
175
// Select and delete nodes
176
canvasOperations.setNodeSelected('node-1', true);
177
canvasOperations.deleteNode('node-1');
178
```
179
180
### Canvas Layout
181
182
Automatic node layout and arrangement functionality.
183
184
```typescript { .api }
185
/**
186
* Composable for canvas layout operations
187
*/
188
function useCanvasLayout(): {
189
layout(target: 'all' | 'selection'): void;
190
getLayoutedElements(nodes: CanvasNode[], connections: CanvasConnection[]): {
191
nodes: CanvasNode[];
192
connections: CanvasConnection[];
193
};
194
arrangeNodes(nodes: INodeUi[], direction?: 'horizontal' | 'vertical'): INodeUi[];
195
};
196
197
/**
198
* Automatically arrange nodes on canvas
199
* @param target - Whether to layout all nodes or just selected ones
200
*/
201
function layout(target: 'all' | 'selection'): void;
202
203
/**
204
* Calculate optimal positions for nodes and connections
205
* @param nodes - Canvas nodes to layout
206
* @param connections - Canvas connections
207
* @returns Layouted elements with new positions
208
*/
209
function getLayoutedElements(
210
nodes: CanvasNode[],
211
connections: CanvasConnection[]
212
): {
213
nodes: CanvasNode[];
214
connections: CanvasConnection[];
215
};
216
```
217
218
### Canvas Node Composable
219
220
Composable for accessing canvas node data within node components.
221
222
```typescript { .api }
223
/**
224
* Composable for accessing canvas node data
225
*/
226
function useCanvasNode(): UseCanvasNodeReturn;
227
228
interface UseCanvasNodeReturn {
229
node: InjectedCanvasNode;
230
id: ComputedRef<string>;
231
name: ComputedRef<string>;
232
label: ComputedRef<string>;
233
subtitle: ComputedRef<string>;
234
inputs: ComputedRef<CanvasConnectionPort[]>;
235
outputs: ComputedRef<CanvasConnectionPort[]>;
236
isDisabled: ComputedRef<boolean>;
237
isReadOnly: ComputedRef<boolean>;
238
isSelected: ComputedRef<boolean>;
239
hasPinnedData: ComputedRef<boolean>;
240
hasIssues: ComputedRef<boolean>;
241
executionRunning: ComputedRef<boolean>;
242
executionWaiting: ComputedRef<boolean>;
243
executionStatus: ComputedRef<ExecutionStatus | undefined>;
244
}
245
246
interface InjectedCanvasNode {
247
id: string;
248
label: string;
249
data: CanvasNodeData;
250
}
251
```
252
253
### Canvas Utilities
254
255
Utility functions for canvas positioning and calculations.
256
257
```typescript { .api }
258
/**
259
* Calculate new node position avoiding conflicts
260
* @param nodes - Existing nodes
261
* @param position - Initial position
262
* @param options - Position calculation options
263
* @returns Conflict-free position
264
*/
265
function getNewNodePosition(
266
nodes: INodeUi[],
267
position: XYPosition,
268
options?: {
269
offsetX?: number;
270
offsetY?: number;
271
gridSize?: number;
272
}
273
): XYPosition;
274
275
/**
276
* Snap position to grid alignment
277
* @param position - Position to snap
278
* @param gridSize - Grid size for snapping
279
* @returns Grid-aligned position
280
*/
281
function snapPositionToGrid(position: XYPosition, gridSize?: number): XYPosition;
282
283
/**
284
* Get center position of canvas viewport
285
* @param scale - Current canvas scale
286
* @param offset - Current canvas offset
287
* @returns Center position coordinates
288
*/
289
function getMidCanvasPosition(scale: number, offset: XYPosition): XYPosition;
290
291
/**
292
* Calculate node dimensions based on configuration
293
* @param isConfiguration - Whether node is in configuration mode
294
* @param isConfigurable - Whether node is configurable
295
* @param inputCount - Number of input ports
296
* @param outputCount - Number of output ports
297
* @param nonMainInputCount - Number of non-main inputs
298
* @returns Node dimensions [width, height]
299
*/
300
function calculateNodeSize(
301
isConfiguration: boolean,
302
isConfigurable: boolean,
303
inputCount: number,
304
outputCount: number,
305
nonMainInputCount: number
306
): [number, number];
307
308
// Canvas constants
309
const GRID_SIZE = 16;
310
const DEFAULT_NODE_SIZE: [number, number] = [96, 96];
311
const CONFIGURATION_NODE_SIZE: [number, number] = [80, 80];
312
const DEFAULT_START_POSITION_X = 176;
313
const DEFAULT_START_POSITION_Y = 240;
314
```
315
316
### Canvas Event System
317
318
Event bus system for canvas communication.
319
320
```typescript { .api }
321
interface CanvasEventBusEvents {
322
fitView: never;
323
'nodes:select': { ids: string[] };
324
'nodes:action': { ids: string[]; action: string };
325
'nodes:delete': { ids: string[] };
326
'saved:workflow': never;
327
'open:contextmenu': { event: MouseEvent; type: 'canvas' | 'node'; nodeId?: string };
328
}
329
330
/**
331
* Canvas event bus for component communication
332
*/
333
interface EventBus<T> {
334
emit<K extends keyof T>(event: K, ...args: T[K] extends never ? [] : [T[K]]): void;
335
on<K extends keyof T>(event: K, handler: T[K] extends never ? () => void : (arg: T[K]) => void): void;
336
off<K extends keyof T>(event: K, handler: Function): void;
337
}
338
```
339
340
### Canvas Navigation
341
342
Canvas viewport navigation and zoom controls.
343
344
```typescript { .api }
345
/**
346
* Canvas navigation and zoom functionality
347
*/
348
interface CanvasNavigation {
349
fitView(): void;
350
zoomIn(): void;
351
zoomOut(): void;
352
zoomToFit(): void;
353
resetView(): void;
354
panTo(position: XYPosition): void;
355
setViewport(viewport: CanvasViewport): void;
356
}
357
358
interface CanvasViewport {
359
x: number;
360
y: number;
361
zoom: number;
362
}
363
364
interface IZoomConfig {
365
scale: number;
366
offset: XYPosition;
367
origin?: XYPosition;
368
}
369
```
370
371
## Types
372
373
```typescript { .api }
374
type XYPosition = [number, number];
375
376
interface CanvasElement {
377
id: string;
378
type: 'node' | 'connection';
379
position?: XYPosition;
380
data?: any;
381
}
382
383
interface CanvasConnection {
384
id: string;
385
source: string;
386
target: string;
387
sourceHandle?: string;
388
targetHandle?: string;
389
type?: string;
390
data?: any;
391
}
392
393
interface EndpointStyle {
394
width?: number;
395
height?: number;
396
fill?: string;
397
stroke?: string;
398
outlineStroke?: string;
399
lineWidth?: number;
400
hover?: boolean;
401
showOutputLabel?: boolean;
402
size?: string;
403
hoverMessage?: string;
404
}
405
406
interface IBounds {
407
minX: number;
408
minY: number;
409
maxX: number;
410
maxY: number;
411
}
412
413
type DraggableMode = 'mapping' | 'panel-resize' | 'move';
414
415
enum CanvasNodeRenderType {
416
Default = 'default',
417
StickyNote = 'sticky-note',
418
Configuration = 'configuration'
419
}
420
421
interface CanvasNodeRenderOptions {
422
configurable?: boolean;
423
configuration?: boolean;
424
trigger?: boolean;
425
}
426
```