0

Referencing https://jqueryui.com/draggable/ i am able to implement a drag drop feature within a parent element (e.g. div). However my need is to have this draggable feature to work within a polygonal element (Like a SVG polygon). I have been searching the net, however there are examples of how to make a svg polygon draggable but not 'how to contain drag drop feature within a polygonal parent (div).

Any ideas / pointers will be helpful.

Thanks.

shoab
  • 545
  • 3
  • 7
  • 19

1 Answers1

0

The short story is you need a function to check if a point is within a polygon, and then check if the four corners of your draggable object are within that shape.

Here's a rough example of doing that, using the draggable sample from jQuery, along with a point in polygon function from this answer. This example is far from perfect, but I hope it points you in the right direction.

// These are the points from the polygon
var polyPoints = [
  [200, 27],
  [364, 146],
  [301, 339],
  [98, 339],
  [35, 146]
];

$("#draggable").draggable({
  drag: function(e, ui) {
    var element = $("#draggable")[0];
    var rect = element.getBoundingClientRect();
    var rectPoints = rect2points(rect);
    
    let inside = true;
    rectPoints.forEach(p => {
      if(!pointInside(p, polyPoints)){
        inside = false;
      }
    });
    $("#draggable")[inside ? 'addClass' : 'removeClass']('inside').text(inside ? 'Yay!' : 'Boo!');
  }
});

function rect2points(rect) {
  return ([
    [rect.left, rect.top],
    [rect.right, rect.top],
    [rect.right, rect.bottom],
    [rect.left, rect.bottom]
  ]);
};

function pointInside(point, vs) {
  var x = point[0],
    y = point[1];

  var inside = false;
  for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
    var xi = vs[i][0],
      yi = vs[i][1];
    var xj = vs[j][0],
      yj = vs[j][1];

    var intersect = ((yi > y) != (yj > y)) &&
      (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }

  return inside;
};
#draggable {
  width: 100px;
  height: 80px;
  background: red;
  position: absolute;
  text-align: center;
  padding-top: 20px;
  color:#fff;
}
#draggable.inside{
  background: green;
}
html, body{
  margin: 0;
}
<script src="//code.jquery.com/jquery-1.12.4.js"></script>
<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>


<div id="draggable">Drag me</div>
<svg width="400px" height="400px" viewBox="0 0 400 400">
  <rect width="600" height="600" fill="#efefef"></rect>
  <polygon points="200,27 364,146 301,339 98,339 35,146" fill="rgba(255,200,0, 1)" stroke="rgba(255,0,0,0.2" stroke-width="2"></polygon>
</svg>
Ted
  • 14,757
  • 2
  • 41
  • 58