or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-components.mdindex.mdinteractions.mdshapes.mdutilities.md

interactions.mddocs/

0

# Event Handling and Interactions

1

2

Comprehensive event system and interactive components for React Konva. This includes mouse, touch, pointer, and drag events, as well as interactive transformation capabilities for creating engaging canvas applications.

3

4

## Capabilities

5

6

### Event System

7

8

React Konva provides a comprehensive event system that maps Konva events to React props, supporting all modern interaction patterns including mouse, touch, pointer, and custom events.

9

10

```typescript { .api }

11

/**

12

* Comprehensive event interface for all Konva components

13

* Supports mouse, touch, pointer, drag, and transform events

14

*/

15

interface KonvaNodeEvents {

16

// Mouse events

17

onMouseOver?(evt: Konva.KonvaEventObject<MouseEvent>): void;

18

onMouseMove?(evt: Konva.KonvaEventObject<MouseEvent>): void;

19

onMouseOut?(evt: Konva.KonvaEventObject<MouseEvent>): void;

20

onMouseEnter?(evt: Konva.KonvaEventObject<MouseEvent>): void;

21

onMouseLeave?(evt: Konva.KonvaEventObject<MouseEvent>): void;

22

onMouseDown?(evt: Konva.KonvaEventObject<MouseEvent>): void;

23

onMouseUp?(evt: Konva.KonvaEventObject<MouseEvent>): void;

24

onWheel?(evt: Konva.KonvaEventObject<WheelEvent>): void;

25

onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;

26

onDblClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;

27

28

// Touch events

29

onTouchStart?(evt: Konva.KonvaEventObject<TouchEvent>): void;

30

onTouchMove?(evt: Konva.KonvaEventObject<TouchEvent>): void;

31

onTouchEnd?(evt: Konva.KonvaEventObject<TouchEvent>): void;

32

onTap?(evt: Konva.KonvaEventObject<Event>): void;

33

onDblTap?(evt: Konva.KonvaEventObject<Event>): void;

34

35

// Drag events

36

onDragStart?(evt: Konva.KonvaEventObject<DragEvent>): void;

37

onDragMove?(evt: Konva.KonvaEventObject<DragEvent>): void;

38

onDragEnd?(evt: Konva.KonvaEventObject<DragEvent>): void;

39

40

// Transform events

41

onTransform?(evt: Konva.KonvaEventObject<Event>): void;

42

onTransformStart?(evt: Konva.KonvaEventObject<Event>): void;

43

onTransformEnd?(evt: Konva.KonvaEventObject<Event>): void;

44

45

// Pointer events

46

onPointerDown?(evt: Konva.KonvaEventObject<PointerEvent>): void;

47

onPointerMove?(evt: Konva.KonvaEventObject<PointerEvent>): void;

48

onPointerUp?(evt: Konva.KonvaEventObject<PointerEvent>): void;

49

onPointerCancel?(evt: Konva.KonvaEventObject<PointerEvent>): void;

50

onPointerEnter?(evt: Konva.KonvaEventObject<PointerEvent>): void;

51

onPointerLeave?(evt: Konva.KonvaEventObject<PointerEvent>): void;

52

onPointerOver?(evt: Konva.KonvaEventObject<PointerEvent>): void;

53

onPointerOut?(evt: Konva.KonvaEventObject<PointerEvent>): void;

54

onPointerClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;

55

onPointerDblClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;

56

onGotPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;

57

onLostPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;

58

59

// Context menu

60

onContextMenu?(evt: Konva.KonvaEventObject<PointerEvent>): void;

61

}

62

```

63

64

### Mouse Events

65

66

Standard mouse interaction events for desktop applications.

67

68

**Usage Examples:**

69

70

```typescript

71

import React, { useState } from 'react';

72

import { Stage, Layer, Circle } from 'react-konva';

73

74

// Click and hover interactions

75

const InteractiveCircle = () => {

76

const [color, setColor] = useState('blue');

77

const [position, setPosition] = useState({ x: 100, y: 100 });

78

79

const handleClick = (e) => {

80

setColor(color === 'blue' ? 'red' : 'blue');

81

};

82

83

const handleMouseEnter = () => {

84

document.body.style.cursor = 'pointer';

85

};

86

87

const handleMouseLeave = () => {

88

document.body.style.cursor = 'default';

89

};

90

91

const handleMouseMove = (e) => {

92

const stage = e.target.getStage();

93

const pointerPos = stage.getPointerPosition();

94

console.log('Mouse at:', pointerPos);

95

};

96

97

return (

98

<Stage width={800} height={600}>

99

<Layer>

100

<Circle

101

x={position.x}

102

y={position.y}

103

radius={50}

104

fill={color}

105

onClick={handleClick}

106

onMouseEnter={handleMouseEnter}

107

onMouseLeave={handleMouseLeave}

108

onMouseMove={handleMouseMove}

109

/>

110

</Layer>

111

</Stage>

112

);

113

};

114

115

// Double-click and wheel events

116

const AdvancedMouseEvents = () => {

117

const [scale, setScale] = useState(1);

118

const [strokeWidth, setStrokeWidth] = useState(2);

119

120

const handleDoubleClick = () => {

121

setScale(scale === 1 ? 2 : 1);

122

};

123

124

const handleWheel = (e) => {

125

e.evt.preventDefault();

126

const newStrokeWidth = strokeWidth + (e.evt.deltaY > 0 ? -1 : 1);

127

setStrokeWidth(Math.max(1, Math.min(10, newStrokeWidth)));

128

};

129

130

return (

131

<Stage width={800} height={600}>

132

<Layer>

133

<Circle

134

x={200}

135

y={200}

136

radius={50}

137

fill="green"

138

stroke="darkgreen"

139

strokeWidth={strokeWidth}

140

scaleX={scale}

141

scaleY={scale}

142

onDblClick={handleDoubleClick}

143

onWheel={handleWheel}

144

/>

145

</Layer>

146

</Stage>

147

);

148

};

149

```

150

151

### Touch Events

152

153

Touch interaction events for mobile and tablet applications.

154

155

**Usage Examples:**

156

157

```typescript

158

import React, { useState } from 'react';

159

import { Stage, Layer, Rect } from 'react-konva';

160

161

// Touch interactions

162

const TouchInteractive = () => {

163

const [touches, setTouches] = useState([]);

164

165

const handleTouchStart = (e) => {

166

const touch = e.evt.touches[0];

167

setTouches([{ id: Date.now(), x: touch.clientX, y: touch.clientY }]);

168

};

169

170

const handleTouchMove = (e) => {

171

e.evt.preventDefault();

172

const touch = e.evt.touches[0];

173

setTouches(prev => prev.map(t => ({ ...t, x: touch.clientX, y: touch.clientY })));

174

};

175

176

const handleTouchEnd = () => {

177

setTouches([]);

178

};

179

180

const handleTap = () => {

181

console.log('Tapped!');

182

};

183

184

const handleDoubleTap = () => {

185

console.log('Double tapped!');

186

};

187

188

return (

189

<Stage width={800} height={600}>

190

<Layer>

191

<Rect

192

x={100}

193

y={100}

194

width={200}

195

height={150}

196

fill="orange"

197

onTouchStart={handleTouchStart}

198

onTouchMove={handleTouchMove}

199

onTouchEnd={handleTouchEnd}

200

onTap={handleTap}

201

onDblTap={handleDoubleTap}

202

/>

203

</Layer>

204

</Stage>

205

);

206

};

207

```

208

209

### Drag and Drop

210

211

Drag and drop functionality for moving and repositioning canvas elements.

212

213

**Usage Examples:**

214

215

```typescript

216

import React, { useState } from 'react';

217

import { Stage, Layer, Circle, Rect } from 'react-konva';

218

219

// Basic dragging

220

const DraggableShapes = () => {

221

const [draggedItem, setDraggedItem] = useState(null);

222

223

const handleDragStart = (e) => {

224

setDraggedItem(e.target.name());

225

e.target.moveToTop();

226

};

227

228

const handleDragEnd = (e) => {

229

setDraggedItem(null);

230

console.log('Dropped at:', e.target.position());

231

};

232

233

const handleDragMove = (e) => {

234

// Constrain to bounds

235

const stage = e.target.getStage();

236

const box = e.target.getClientRect();

237

238

const minX = 0;

239

const maxX = stage.width() - box.width;

240

const minY = 0;

241

const maxY = stage.height() - box.height;

242

243

e.target.x(Math.max(minX, Math.min(e.target.x(), maxX)));

244

e.target.y(Math.max(minY, Math.min(e.target.y(), maxY)));

245

};

246

247

return (

248

<Stage width={800} height={600}>

249

<Layer>

250

<Circle

251

x={150}

252

y={150}

253

radius={50}

254

fill="red"

255

name="circle"

256

draggable

257

onDragStart={handleDragStart}

258

onDragEnd={handleDragEnd}

259

onDragMove={handleDragMove}

260

/>

261

<Rect

262

x={300}

263

y={100}

264

width={100}

265

height={100}

266

fill="blue"

267

name="rect"

268

draggable

269

onDragStart={handleDragStart}

270

onDragEnd={handleDragEnd}

271

onDragMove={handleDragMove}

272

/>

273

</Layer>

274

</Stage>

275

);

276

};

277

```

278

279

### Pointer Events

280

281

Modern pointer events for unified handling of mouse, touch, and pen inputs.

282

283

**Usage Examples:**

284

285

```typescript

286

import React, { useState } from 'react';

287

import { Stage, Layer, Line } from 'react-konva';

288

289

// Drawing with pointer events

290

const DrawingCanvas = () => {

291

const [lines, setLines] = useState([]);

292

const [isDrawing, setIsDrawing] = useState(false);

293

294

const handlePointerDown = (e) => {

295

setIsDrawing(true);

296

const pos = e.target.getStage().getPointerPosition();

297

setLines([...lines, { points: [pos.x, pos.y] }]);

298

};

299

300

const handlePointerMove = (e) => {

301

if (!isDrawing) return;

302

303

const stage = e.target.getStage();

304

const point = stage.getPointerPosition();

305

const lastLine = lines[lines.length - 1];

306

307

setLines([

308

...lines.slice(0, -1),

309

{ ...lastLine, points: [...lastLine.points, point.x, point.y] }

310

]);

311

};

312

313

const handlePointerUp = () => {

314

setIsDrawing(false);

315

};

316

317

return (

318

<Stage

319

width={800}

320

height={600}

321

onPointerDown={handlePointerDown}

322

onPointerMove={handlePointerMove}

323

onPointerUp={handlePointerUp}

324

>

325

<Layer>

326

{lines.map((line, i) => (

327

<Line

328

key={i}

329

points={line.points}

330

stroke="black"

331

strokeWidth={2}

332

tension={0.5}

333

lineCap="round"

334

lineJoin="round"

335

/>

336

))}

337

</Layer>

338

</Stage>

339

);

340

};

341

```

342

343

### Transformer Component

344

345

Interactive transformation component for resizing, rotating, and moving shapes with visual handles.

346

347

```typescript { .api }

348

/**

349

* Interactive transformation component

350

* Provides visual handles for resizing, rotating, and moving shapes

351

*/

352

var Transformer: KonvaNodeComponent<Konva.Transformer, Konva.TransformerConfig>;

353

354

interface TransformerConfig extends Konva.NodeConfig {

355

// Target nodes to transform

356

nodes?: Konva.Node[];

357

358

// Resize options

359

enabledAnchors?: string[];

360

rotateEnabled?: boolean;

361

resizeEnabled?: boolean;

362

363

// Styling

364

borderEnabled?: boolean;

365

borderStroke?: string;

366

borderStrokeWidth?: number;

367

borderDash?: number[];

368

369

// Anchors

370

anchorSize?: number;

371

anchorStroke?: string;

372

anchorStrokeWidth?: number;

373

anchorFill?: string;

374

anchorCornerRadius?: number;

375

376

// Behavior

377

keepRatio?: boolean;

378

centeredScaling?: boolean;

379

flipEnabled?: boolean;

380

381

// Boundaries

382

boundBoxFunc?: (oldBox: any, newBox: any) => any;

383

}

384

```

385

386

**Usage Examples:**

387

388

```typescript

389

import React, { useState, useRef } from 'react';

390

import { Stage, Layer, Rect, Circle, Transformer } from 'react-konva';

391

392

// Basic transformer usage

393

const TransformableShapes = () => {

394

const [selectedId, setSelectedId] = useState(null);

395

const trRef = useRef();

396

397

const shapes = [

398

{ id: '1', type: 'rect', x: 100, y: 100, width: 100, height: 100, fill: 'red' },

399

{ id: '2', type: 'circle', x: 300, y: 100, radius: 50, fill: 'blue' }

400

];

401

402

const handleSelect = (id) => {

403

setSelectedId(id);

404

};

405

406

const handleDeselect = (e) => {

407

// Deselect when clicking on empty area

408

if (e.target === e.target.getStage()) {

409

setSelectedId(null);

410

}

411

};

412

413

React.useEffect(() => {

414

if (selectedId) {

415

const selectedNode = stage.findOne(`#${selectedId}`);

416

if (selectedNode && trRef.current) {

417

trRef.current.nodes([selectedNode]);

418

trRef.current.getLayer().batchDraw();

419

}

420

}

421

}, [selectedId]);

422

423

return (

424

<Stage width={800} height={600} onMouseDown={handleDeselect}>

425

<Layer>

426

{shapes.map((shape) => (

427

shape.type === 'rect' ? (

428

<Rect

429

key={shape.id}

430

id={shape.id}

431

x={shape.x}

432

y={shape.y}

433

width={shape.width}

434

height={shape.height}

435

fill={shape.fill}

436

onClick={() => handleSelect(shape.id)}

437

draggable

438

/>

439

) : (

440

<Circle

441

key={shape.id}

442

id={shape.id}

443

x={shape.x}

444

y={shape.y}

445

radius={shape.radius}

446

fill={shape.fill}

447

onClick={() => handleSelect(shape.id)}

448

draggable

449

/>

450

)

451

))}

452

453

{selectedId && (

454

<Transformer

455

ref={trRef}

456

rotateEnabled={true}

457

resizeEnabled={true}

458

enabledAnchors={[

459

'top-left', 'top-center', 'top-right',

460

'middle-right', 'middle-left',

461

'bottom-left', 'bottom-center', 'bottom-right'

462

]}

463

borderEnabled={true}

464

borderStroke="blue"

465

borderStrokeWidth={1}

466

borderDash={[4, 4]}

467

anchorSize={8}

468

anchorStroke="blue"

469

anchorFill="white"

470

anchorStrokeWidth={1}

471

keepRatio={false}

472

onTransformEnd={(e) => {

473

console.log('Transform complete:', e.target.attrs);

474

}}

475

/>

476

)}

477

</Layer>

478

</Stage>

479

);

480

};

481

482

// Advanced transformer with constraints

483

const ConstrainedTransformer = () => {

484

const [selectedId, setSelectedId] = useState(null);

485

const trRef = useRef();

486

487

const boundBoxFunc = (oldBox, newBox) => {

488

// Limit minimum size

489

if (newBox.width < 20 || newBox.height < 20) {

490

return oldBox;

491

}

492

493

// Limit maximum size

494

if (newBox.width > 200 || newBox.height > 200) {

495

return oldBox;

496

}

497

498

return newBox;

499

};

500

501

return (

502

<Stage width={800} height={600}>

503

<Layer>

504

<Rect

505

id="constrained-rect"

506

x={200}

507

y={200}

508

width={100}

509

height={100}

510

fill="green"

511

onClick={() => setSelectedId('constrained-rect')}

512

draggable

513

/>

514

515

{selectedId && (

516

<Transformer

517

ref={trRef}

518

nodes={[]}

519

keepRatio={true}

520

centeredScaling={false}

521

enabledAnchors={['top-left', 'top-right', 'bottom-left', 'bottom-right']}

522

boundBoxFunc={boundBoxFunc}

523

onTransform={(e) => {

524

// Real-time transform feedback

525

console.log('Transforming:', e.target.attrs);

526

}}

527

/>

528

)}

529

</Layer>

530

</Stage>

531

);

532

};

533

```

534

535

### Event Object Properties

536

537

The Konva event object provides access to both the original browser event and Konva-specific information.

538

539

```typescript { .api }

540

/**

541

* Konva event object structure

542

* Provides access to original event and Konva-specific data

543

*/

544

interface KonvaEventObject<T> {

545

evt: T; // Original browser event

546

target: Konva.Node; // Konva node that triggered the event

547

currentTarget: Konva.Node; // Current event target in bubbling phase

548

type: string; // Event type

549

cancelBubble: boolean; // Controls event bubbling

550

}

551

```

552

553

**Usage Examples:**

554

555

```typescript

556

import React from 'react';

557

import { Stage, Layer, Circle } from 'react-konva';

558

559

// Accessing event properties

560

const EventExample = () => {

561

const handleClick = (e) => {

562

// Original browser event

563

console.log('Browser event:', e.evt);

564

565

// Konva node that was clicked

566

console.log('Target node:', e.target);

567

568

// Event type

569

console.log('Event type:', e.type);

570

571

// Stage pointer position

572

const stage = e.target.getStage();

573

const pointerPos = stage.getPointerPosition();

574

console.log('Pointer position:', pointerPos);

575

576

// Node position

577

console.log('Node position:', e.target.position());

578

579

// Prevent event bubbling

580

e.cancelBubble = true;

581

};

582

583

return (

584

<Stage width={800} height={600}>

585

<Layer onClick={() => console.log('Layer clicked')}>

586

<Circle

587

x={200}

588

y={200}

589

radius={50}

590

fill="purple"

591

onClick={handleClick}

592

/>

593

</Layer>

594

</Stage>

595

);

596

};

597

```