Skip to main content

HTML5 Canvas Complex Drag and Drop Bounds

To bound the movement of nodes being dragged and dropped inside regions with Konva, we can use the dragmove event to define boundaries that the node cannot cross.

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 light blue rectangle and observe that it is bound below an imaginary boundary at y = 50. Drag and drop the yellow rectangle and observe that it is bound inside of an imaginary circle.

import Konva from 'konva';

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight,
});

const layer = new Konva.Layer();

const blueGroup = new Konva.Group({
x: 30,
y: 70,
draggable: true,
});

// bound below y=50

blueGroup.on('dragmove', () => {
blueGroup.y(Math.max(blueGroup.y(), 50));
});

// bound inside a circle

const yellowGroup = new Konva.Group({
x: stage.width() / 2,
y: 70,
draggable: true,
});

yellowGroup.on('dragmove', () => {
const x = stage.width() / 2;
const y = 70;
const radius = 50;
const pos = yellowGroup.absolutePosition();
const scale = radius / Math.sqrt(Math.pow(pos.x - x, 2) + Math.pow(pos.y - y, 2));

if (scale < 1) {
yellowGroup.x(Math.round((pos.x - x) * scale + x));
yellowGroup.y(Math.round((pos.y - y) * scale + y));
}
});

const blueText = new Konva.Text({
fontSize: 26,
fontFamily: 'Calibri',
text: 'bound below',
fill: 'black',
padding: 10,
width: 150,
align: 'center',
});

const blueRect = new Konva.Rect({
width: 150,
height: 72,
fill: '#aaf',
stroke: 'black',
strokeWidth: 4,
});

const yellowText = new Konva.Text({
fontSize: 26,
fontFamily: 'Calibri',
text: 'bound in circle',
fill: 'black',
padding: 10,
width: 150,
align: 'center',
});

const yellowRect = new Konva.Rect({
width: 150,
height:72,
fill: 'yellow',
stroke: 'black',
strokeWidth: 4,
});

blueGroup.add(blueRect).add(blueText);
yellowGroup.add(yellowRect).add(yellowText);

layer.add(blueGroup);
layer.add(yellowGroup);
stage.add(layer);