React binding to canvas element via Konva framework providing declarative and reactive canvas graphics.
—
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.
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.
/**
* Comprehensive event interface for all Konva components
* Supports mouse, touch, pointer, drag, and transform events
*/
interface KonvaNodeEvents {
// Mouse events
onMouseOver?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseMove?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseOut?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseEnter?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseLeave?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseDown?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onMouseUp?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onWheel?(evt: Konva.KonvaEventObject<WheelEvent>): void;
onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
onDblClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
// Touch events
onTouchStart?(evt: Konva.KonvaEventObject<TouchEvent>): void;
onTouchMove?(evt: Konva.KonvaEventObject<TouchEvent>): void;
onTouchEnd?(evt: Konva.KonvaEventObject<TouchEvent>): void;
onTap?(evt: Konva.KonvaEventObject<Event>): void;
onDblTap?(evt: Konva.KonvaEventObject<Event>): void;
// Drag events
onDragStart?(evt: Konva.KonvaEventObject<DragEvent>): void;
onDragMove?(evt: Konva.KonvaEventObject<DragEvent>): void;
onDragEnd?(evt: Konva.KonvaEventObject<DragEvent>): void;
// Transform events
onTransform?(evt: Konva.KonvaEventObject<Event>): void;
onTransformStart?(evt: Konva.KonvaEventObject<Event>): void;
onTransformEnd?(evt: Konva.KonvaEventObject<Event>): void;
// Pointer events
onPointerDown?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerMove?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerUp?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerCancel?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerEnter?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerLeave?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerOver?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerOut?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onPointerDblClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onGotPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
onLostPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
// Context menu
onContextMenu?(evt: Konva.KonvaEventObject<PointerEvent>): void;
}Standard mouse interaction events for desktop applications.
Usage Examples:
import React, { useState } from 'react';
import { Stage, Layer, Circle } from 'react-konva';
// Click and hover interactions
const InteractiveCircle = () => {
const [color, setColor] = useState('blue');
const [position, setPosition] = useState({ x: 100, y: 100 });
const handleClick = (e) => {
setColor(color === 'blue' ? 'red' : 'blue');
};
const handleMouseEnter = () => {
document.body.style.cursor = 'pointer';
};
const handleMouseLeave = () => {
document.body.style.cursor = 'default';
};
const handleMouseMove = (e) => {
const stage = e.target.getStage();
const pointerPos = stage.getPointerPosition();
console.log('Mouse at:', pointerPos);
};
return (
<Stage width={800} height={600}>
<Layer>
<Circle
x={position.x}
y={position.y}
radius={50}
fill={color}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onMouseMove={handleMouseMove}
/>
</Layer>
</Stage>
);
};
// Double-click and wheel events
const AdvancedMouseEvents = () => {
const [scale, setScale] = useState(1);
const [strokeWidth, setStrokeWidth] = useState(2);
const handleDoubleClick = () => {
setScale(scale === 1 ? 2 : 1);
};
const handleWheel = (e) => {
e.evt.preventDefault();
const newStrokeWidth = strokeWidth + (e.evt.deltaY > 0 ? -1 : 1);
setStrokeWidth(Math.max(1, Math.min(10, newStrokeWidth)));
};
return (
<Stage width={800} height={600}>
<Layer>
<Circle
x={200}
y={200}
radius={50}
fill="green"
stroke="darkgreen"
strokeWidth={strokeWidth}
scaleX={scale}
scaleY={scale}
onDblClick={handleDoubleClick}
onWheel={handleWheel}
/>
</Layer>
</Stage>
);
};Touch interaction events for mobile and tablet applications.
Usage Examples:
import React, { useState } from 'react';
import { Stage, Layer, Rect } from 'react-konva';
// Touch interactions
const TouchInteractive = () => {
const [touches, setTouches] = useState([]);
const handleTouchStart = (e) => {
const touch = e.evt.touches[0];
setTouches([{ id: Date.now(), x: touch.clientX, y: touch.clientY }]);
};
const handleTouchMove = (e) => {
e.evt.preventDefault();
const touch = e.evt.touches[0];
setTouches(prev => prev.map(t => ({ ...t, x: touch.clientX, y: touch.clientY })));
};
const handleTouchEnd = () => {
setTouches([]);
};
const handleTap = () => {
console.log('Tapped!');
};
const handleDoubleTap = () => {
console.log('Double tapped!');
};
return (
<Stage width={800} height={600}>
<Layer>
<Rect
x={100}
y={100}
width={200}
height={150}
fill="orange"
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onTap={handleTap}
onDblTap={handleDoubleTap}
/>
</Layer>
</Stage>
);
};Drag and drop functionality for moving and repositioning canvas elements.
Usage Examples:
import React, { useState } from 'react';
import { Stage, Layer, Circle, Rect } from 'react-konva';
// Basic dragging
const DraggableShapes = () => {
const [draggedItem, setDraggedItem] = useState(null);
const handleDragStart = (e) => {
setDraggedItem(e.target.name());
e.target.moveToTop();
};
const handleDragEnd = (e) => {
setDraggedItem(null);
console.log('Dropped at:', e.target.position());
};
const handleDragMove = (e) => {
// Constrain to bounds
const stage = e.target.getStage();
const box = e.target.getClientRect();
const minX = 0;
const maxX = stage.width() - box.width;
const minY = 0;
const maxY = stage.height() - box.height;
e.target.x(Math.max(minX, Math.min(e.target.x(), maxX)));
e.target.y(Math.max(minY, Math.min(e.target.y(), maxY)));
};
return (
<Stage width={800} height={600}>
<Layer>
<Circle
x={150}
y={150}
radius={50}
fill="red"
name="circle"
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDragMove={handleDragMove}
/>
<Rect
x={300}
y={100}
width={100}
height={100}
fill="blue"
name="rect"
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDragMove={handleDragMove}
/>
</Layer>
</Stage>
);
};Modern pointer events for unified handling of mouse, touch, and pen inputs.
Usage Examples:
import React, { useState } from 'react';
import { Stage, Layer, Line } from 'react-konva';
// Drawing with pointer events
const DrawingCanvas = () => {
const [lines, setLines] = useState([]);
const [isDrawing, setIsDrawing] = useState(false);
const handlePointerDown = (e) => {
setIsDrawing(true);
const pos = e.target.getStage().getPointerPosition();
setLines([...lines, { points: [pos.x, pos.y] }]);
};
const handlePointerMove = (e) => {
if (!isDrawing) return;
const stage = e.target.getStage();
const point = stage.getPointerPosition();
const lastLine = lines[lines.length - 1];
setLines([
...lines.slice(0, -1),
{ ...lastLine, points: [...lastLine.points, point.x, point.y] }
]);
};
const handlePointerUp = () => {
setIsDrawing(false);
};
return (
<Stage
width={800}
height={600}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
>
<Layer>
{lines.map((line, i) => (
<Line
key={i}
points={line.points}
stroke="black"
strokeWidth={2}
tension={0.5}
lineCap="round"
lineJoin="round"
/>
))}
</Layer>
</Stage>
);
};Interactive transformation component for resizing, rotating, and moving shapes with visual handles.
/**
* Interactive transformation component
* Provides visual handles for resizing, rotating, and moving shapes
*/
var Transformer: KonvaNodeComponent<Konva.Transformer, Konva.TransformerConfig>;
interface TransformerConfig extends Konva.NodeConfig {
// Target nodes to transform
nodes?: Konva.Node[];
// Resize options
enabledAnchors?: string[];
rotateEnabled?: boolean;
resizeEnabled?: boolean;
// Styling
borderEnabled?: boolean;
borderStroke?: string;
borderStrokeWidth?: number;
borderDash?: number[];
// Anchors
anchorSize?: number;
anchorStroke?: string;
anchorStrokeWidth?: number;
anchorFill?: string;
anchorCornerRadius?: number;
// Behavior
keepRatio?: boolean;
centeredScaling?: boolean;
flipEnabled?: boolean;
// Boundaries
boundBoxFunc?: (oldBox: any, newBox: any) => any;
}Usage Examples:
import React, { useState, useRef } from 'react';
import { Stage, Layer, Rect, Circle, Transformer } from 'react-konva';
// Basic transformer usage
const TransformableShapes = () => {
const [selectedId, setSelectedId] = useState(null);
const trRef = useRef();
const shapes = [
{ id: '1', type: 'rect', x: 100, y: 100, width: 100, height: 100, fill: 'red' },
{ id: '2', type: 'circle', x: 300, y: 100, radius: 50, fill: 'blue' }
];
const handleSelect = (id) => {
setSelectedId(id);
};
const handleDeselect = (e) => {
// Deselect when clicking on empty area
if (e.target === e.target.getStage()) {
setSelectedId(null);
}
};
React.useEffect(() => {
if (selectedId) {
const selectedNode = stage.findOne(`#${selectedId}`);
if (selectedNode && trRef.current) {
trRef.current.nodes([selectedNode]);
trRef.current.getLayer().batchDraw();
}
}
}, [selectedId]);
return (
<Stage width={800} height={600} onMouseDown={handleDeselect}>
<Layer>
{shapes.map((shape) => (
shape.type === 'rect' ? (
<Rect
key={shape.id}
id={shape.id}
x={shape.x}
y={shape.y}
width={shape.width}
height={shape.height}
fill={shape.fill}
onClick={() => handleSelect(shape.id)}
draggable
/>
) : (
<Circle
key={shape.id}
id={shape.id}
x={shape.x}
y={shape.y}
radius={shape.radius}
fill={shape.fill}
onClick={() => handleSelect(shape.id)}
draggable
/>
)
))}
{selectedId && (
<Transformer
ref={trRef}
rotateEnabled={true}
resizeEnabled={true}
enabledAnchors={[
'top-left', 'top-center', 'top-right',
'middle-right', 'middle-left',
'bottom-left', 'bottom-center', 'bottom-right'
]}
borderEnabled={true}
borderStroke="blue"
borderStrokeWidth={1}
borderDash={[4, 4]}
anchorSize={8}
anchorStroke="blue"
anchorFill="white"
anchorStrokeWidth={1}
keepRatio={false}
onTransformEnd={(e) => {
console.log('Transform complete:', e.target.attrs);
}}
/>
)}
</Layer>
</Stage>
);
};
// Advanced transformer with constraints
const ConstrainedTransformer = () => {
const [selectedId, setSelectedId] = useState(null);
const trRef = useRef();
const boundBoxFunc = (oldBox, newBox) => {
// Limit minimum size
if (newBox.width < 20 || newBox.height < 20) {
return oldBox;
}
// Limit maximum size
if (newBox.width > 200 || newBox.height > 200) {
return oldBox;
}
return newBox;
};
return (
<Stage width={800} height={600}>
<Layer>
<Rect
id="constrained-rect"
x={200}
y={200}
width={100}
height={100}
fill="green"
onClick={() => setSelectedId('constrained-rect')}
draggable
/>
{selectedId && (
<Transformer
ref={trRef}
nodes={[]}
keepRatio={true}
centeredScaling={false}
enabledAnchors={['top-left', 'top-right', 'bottom-left', 'bottom-right']}
boundBoxFunc={boundBoxFunc}
onTransform={(e) => {
// Real-time transform feedback
console.log('Transforming:', e.target.attrs);
}}
/>
)}
</Layer>
</Stage>
);
};The Konva event object provides access to both the original browser event and Konva-specific information.
/**
* Konva event object structure
* Provides access to original event and Konva-specific data
*/
interface KonvaEventObject<T> {
evt: T; // Original browser event
target: Konva.Node; // Konva node that triggered the event
currentTarget: Konva.Node; // Current event target in bubbling phase
type: string; // Event type
cancelBubble: boolean; // Controls event bubbling
}Usage Examples:
import React from 'react';
import { Stage, Layer, Circle } from 'react-konva';
// Accessing event properties
const EventExample = () => {
const handleClick = (e) => {
// Original browser event
console.log('Browser event:', e.evt);
// Konva node that was clicked
console.log('Target node:', e.target);
// Event type
console.log('Event type:', e.type);
// Stage pointer position
const stage = e.target.getStage();
const pointerPos = stage.getPointerPosition();
console.log('Pointer position:', pointerPos);
// Node position
console.log('Node position:', e.target.position());
// Prevent event bubbling
e.cancelBubble = true;
};
return (
<Stage width={800} height={600}>
<Layer onClick={() => console.log('Layer clicked')}>
<Circle
x={200}
y={200}
radius={50}
fill="purple"
onClick={handleClick}
/>
</Layer>
</Stage>
);
};Install with Tessl CLI
npx tessl i tessl/npm-react-konva