I am using Konva to drag and detect collision, that works, but what I want to do is prevent to be able to drag over an item when the collision has been detected, I am not able to.
Sample code:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@9.3.15/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Drag and Drop Collision Detection Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
stage.add(layer);
function createShape() {
var group = new Konva.Group({
x: Math.random() * width,
y: Math.random() * height,
draggable: true,
});
var shape = new Konva.Rect({
width: 30 + Math.random() * 30,
height: 30 + Math.random() * 30,
fill: 'grey',
rotation: 360 * Math.random(),
name: 'fillShape',
});
group.add(shape);
var boundingBox = shape.getClientRect({ relativeTo: group });
var box = new Konva.Rect({
x: boundingBox.x,
y: boundingBox.y,
width: boundingBox.width,
height: boundingBox.height,
stroke: 'red',
strokeWidth: 1,
});
group.add(box);
return group;
}
for (var i = 0; i < 10; i++) {
layer.add(createShape());
}
layer.on('dragmove', function (e) {
var target = e.target;
var targetRect = e.target.getClientRect();
layer.children.forEach(function (group) {
// do not check intersection with itself
if (group === target) {
return;
}
if (haveIntersection(group.getClientRect(), targetRect)) {
console.log('tar', target);
console.log('tarRec', targetRect);
group.findOne('.fillShape').fill('red');
target.attrs.x(target._lastPos.x);
} else {
group.findOne('.fillShape').fill('grey');
}
});
});
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
</script>
</body>
</html>
The stopDrag() works on the code above.
The only problem I have, is I use react-konva with component, unfortunately I am unable to provide an example, as it is data sensitive. When happens is that when the objects collide, the drag stops as expected, but when I try to drag it again, I need to drag it a small part downwards (when colliding at the bottom), as that small part is what is allowing it, after that I need to mouse-click again and hold to drag it again normally.
It seems there still is a small space around the collided item what prevents the dragging.
Hm well it’s hard to tell then what the actual problem is. Can you isolate the issue (e.g. a certain parameter being set) and reproduce it in your vanilla JS example above? Otherwise it might as well be a bug in the react-konva implementation itself…
I did try both methods, but wasn’t aware of that. Maybe worth a peek under the hood of Konva to see if there is anything that stands out in that regard.
The documentation has a comprehensive library of code examples, which is nice to see. This is a better thought out example of snapping.
I am wondering, with my example, how difficult it would be to implement this in vanilla js, but maybe save that for another time
edit: Actually I just spotted this react implementation in the comments at the bottom of the link I posted.
… and the position() shorthand is just derived from those methods here.
I wasn’t exactly trying to implement that snap behaviour though, but rather a complete stop where dragging would continue when leaving the colliding node. Anyway I guess I was just messing up something else. (-:
I have been trying to play with the snapping, but something weird is happening. When object collides on drag, it somehow positioned the target.x at the center (x) of the object it collides with. I have been using the code and modified it to use with react components layout (instead of vanilla JS). This is the code for the react-konva: https://konvajs.org/docs/react/index.html
This is kinda the layout I am using:
<Stage>
<Layer>
<Group>
<Rect /> // this is to have a white rectangle for the content area
<Group>
<Image />
</Group>
<Group>
<Image />
</Group>
</Group>
</Layer>
</Stage>