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
```