HTML5 Canvas Simple Drag Bounds Tutorial
To restrict the movement of shapes being dragged and dropped with Konva,
we can use the dragmove event and override the drag and drop position inside of it.
This event can be used to constrain the drag and drop movement in all kinds of ways, such as constraining the motion horizontally, vertically, diagonally, or radially, or even constrain the node to stay inside of a box, circle, or any other path.
shape.on('dragmove', () => {
// lock position of the shape on x axis
// keep y position as is
shape.x(0);
});
Tip: you can use shape.absolutePosition() method to get/set absolute position of a node, instead of relative x and y.
Instructions: Drag and drop the horizontal text and observe that it can only move horizontally. Drag and drop the vertical text and observe that it can only move vertically.
- Vanilla
- React
- Vue
import Konva from 'konva';
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
const layer = new Konva.Layer();
stage.add(layer);
const horizontalText = new Konva.Text({
x: 50,
y: 50,
text: 'Drag me horizontally',
fontSize: 16,
draggable: true,
fill: 'black',
});
horizontalText.on('dragmove', function () {
// horizontal only
this.y(50);
});
const verticalText = new Konva.Text({
x: 200,
y: 50,
text: 'Drag me vertically',
fontSize: 16,
draggable: true,
fill: 'black',
});
verticalText.on('dragmove', function () {
// vertical only
this.x(200);
});
layer.add(horizontalText);
layer.add(verticalText);
import { Stage, Layer, Text } from 'react-konva';
import { useState } from 'react';
const App = () => {
const [horizontalPosition, setHorizontalPosition] = useState({ x: 50, y: 50 });
const [verticalPosition, setVerticalPosition] = useState({ x: 200, y: 50 });
const handleHorizontalDragMove = (e) => {
// The y prop stays 50, so React-Konva will not reapply it after a drag.
// Constrain the node directly, then save its actual position in state.
e.target.y(50);
setHorizontalPosition(e.target.position());
};
const handleVerticalDragMove = (e) => {
// The x prop stays 200, so a state update alone cannot lock this axis.
e.target.x(200);
setVerticalPosition(e.target.position());
};
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Text
x={horizontalPosition.x}
y={horizontalPosition.y}
text="Drag me horizontally"
fontSize={16}
draggable
fill="black"
onDragMove={handleHorizontalDragMove}
/>
<Text
x={verticalPosition.x}
y={verticalPosition.y}
text="Drag me vertically"
fontSize={16}
draggable
fill="black"
onDragMove={handleVerticalDragMove}
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageSize">
<v-layer>
<v-text
:config="horizontalTextConfig"
@dragmove="handleHorizontalDragMove"
/>
<v-text
:config="verticalTextConfig"
@dragmove="handleVerticalDragMove"
/>
</v-layer>
</v-stage>
</template>
<script setup>
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const horizontalTextConfig = {
x: 50,
y: 50,
text: 'Drag me horizontally',
fontSize: 16,
draggable: true,
fill: 'black'
};
const verticalTextConfig = {
x: 200,
y: 50,
text: 'Drag me vertically',
fontSize: 16,
draggable: true,
fill: 'black'
};
const handleHorizontalDragMove = (e) => {
e.target.y(50);
};
const handleVerticalDragMove = (e) => {
e.target.x(200);
};
</script>