or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-client.mdcanvas-operations.mdcomponent-system.mdcomposables.mdindex.mdstate-management.mdworkflow-management.md

canvas-operations.mddocs/

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

```