سؤال

I have been trying to get jQuery UI's draggable/droppable to work properly with round elements, but it seems that all of the methods I've tried make elements visually round, but they are still treated like squares.

The specific issue I am having is when using a droppable with a border-radius or clip-path, the draggable can be dropped on the "corners" that should not be there...

To better illustrate my issue:

Border-radius Example

<div class="droppable"></div>
<div class="draggable"></div>

.droppable {
    position:relative;
    background:green;
    height:200px;
    width:200px;
    border-radius: 50%;
}
.draggable {
    background:black;
    height: 25px;
    width: 25px;
}
.touched {
    background:red;
}

$('.draggable').draggable();
$('.droppable').droppable({
    tolerance: 'touch',
    over: function () {
        $(this).addClass('touched');
    }
});

Clip-path Example

<svg width="0" height="0">
    <clipPath id="clipping">
        <circle cx="100" cy="100" r="100" />
    </clipPath>
</svg>

.droppable {
    position:relative;
    background:green;
    width:200px;
    height:200px;
    clip-path: url(#clipping);
}

I have dug through the API Documentation for both Draggable and Droppable and I've searched for other ways to create circular/round elements, hence clip-path, but haven't been able to come up with a work-around.

Is there any way to get draggable and droppable to treat round elements like round elements?

هل كانت مفيدة؟

المحلول

Here is a way it could be solved with some additional JS:

$('.draggable').draggable({
   drag: function (aEvent, aUi) {

      $(".droppable").each(function() {

         var myX = aUi.offset.left;
         var myY = aUi.offset.top;

         var myR = $(this).outerWidth() / 2;
         var myCX = $(this).offset().left + myR;
         var myCY = $(this).offset().top + myR;

         if (checkIntersection(myX, myY, myCX, myCY, myR))
         {
             $(this).addClass('touched');
         }
     });
   }    
});
$('.droppable').droppable({
   tolerance: 'touch'
});

function checkIntersection(aX, aY, aCX, aCY, aR) {
   return (Math.pow(aX - aCX, 2) + Math.pow(aY - aCY, 2) < Math.pow(aR, 2));
}

So here is what I did:

  1. I moved the function to the drag event of the draggable as this gets called over and over and so we can constantly check if we are now in the circle.

  2. There is an .each() loop as you now have to check every droppable in turn.

  3. I am checking whether or not the x and y coordinates of the draggable overlap with the droppable. This is done in the function checkIntersection. For a full explanation of the algorithm used see Equation for testing if a point is inside a circle.

As a note, right now I am only checking the intersection with one of the corners of the little square, you would have to do this for all corners, to be fully precise.

Here is the fiddle: http://jsfiddle.net/V3Hkg/2/

نصائح أخرى

This is because jQuery is defining the draggable/droppable areas via the bounding box of the element, not its visual appearance as defined in CSS. It doesn't know this information by default. Take a look at this tutorial entitled Hover and Click Trigger for Circular Elements with jQuery. Perhaps it will give you insight into how to bind the drag/drop events to only the circular area.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top