Konva collission doesn't stop dragging over element

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>

Hi @skamstra, you might just call e.target.stopDrag() to release the node altogether… would that be the desired behavior?

How do you want to stop dragging over an item when a collision happens?

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 have been having a bit of a play with Konva. The idea being to try and implement some basic snapping as an alternative to stopdrag.

1 Like

Hi @rpg_digital, thanks I will have a look and see if I can fix anything on my end

I’ve been fiddling with position() which didn’t work well, but using just x() and y() for snapping is brilliant. :-)

1 Like

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 :slight_smile:

edit: Actually I just spotted this react implementation in the comments at the bottom of the link I posted.

https://codesandbox.io/p/sandbox/react-konva-snap-1mq1g2

1 Like

Hm no, it’s the same under the hood…

… 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. (-:

1 Like

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>

Here is a codesandbox with what is happening: https://codesandbox.io/p/sandbox/4rp9jq

I don’t use react, so this is very much a case of winging it. This a basic cut back version with some squares.

Edit: Updated with scalable lion images
https://codesandbox.io/p/sandbox/drag-and-drop-forked-2v77xg

Edit2 Updated to work with rotation. Only snaps to the bounding box, rather than a point along the edge at this point.

A codepen (Not react version)

1 Like

Hi @rpg_digital,

I will check the code and see if I can change my code.
Will get back to you after that.

Cheers

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.