2016-03-05 47 views
2

我正在使用JQuery Draggable將項目移動到網格中。對象捕捉到32x32網格區域。如果對象處於相同位置,我希望能夠取消網格捕捉。JQuery Draggable - 防止網格對象在相同位置

拖動不能取消,只能阻止它進入廣場。在阻止並移回到之前的位置後,如果用戶繼續拖入新的未佔用網格位置,則必須與該位置對齊。

我創建了一個服務於上述目的的演示,但圖像在嘗試進入新位置時會出現毛刺,但會被取消回舊位置。

https://jsfiddle.net/dtx7my4e/1/

這裏是在小提琴代碼:

HTML:

​​

的Javascript:

var objects = [ 
    [0, 0], 
    [1, 1] 
]; 

$(function() { 
    $(".drag-item").draggable({ 
     grid: [ 32, 32 ], 
     containment: '.drop-target', 
     drag: function (event, obj){ 
      let objectId = $(this).attr('object-id'); 

      var objectPositionX = $(this).position().left/32; 
      var objectPositionY = $(this).position().top/32; 

      var previousPositionX = Math.floor(objects[objectId][0]); 
      var previousPositionY = Math.floor(objects[objectId][1]); 

      if (objectPositionX != previousPositionX || objectPositionY != previousPositionY) { 
       if(!isObjectInPosition(objects, [objectPositionX, objectPositionY])) { 
        objects[objectId] = [objectPositionX, objectPositionY]; 
       } else { 
        obj.position.left = previousPositionX * 32; 
        obj.position.top = previousPositionY * 32; 
       } 
      } 
     } 
    }); 
}); 


function isObjectInPosition(arrayToSearch, positionToFind) 
{ 
    for (let i = 0; i < arrayToSearch.length; i++) { 
     if (arrayToSearch[i][0] == positionToFind[0] 
       && arrayToSearch[i][1] == positionToFind[1]) { 
      return true; 
     } 
    } 
    return false; 
} 

CSS:

.drag-item { 
    background-image: url("http://i.imgur.com/lBIWrWw.png"); 
    background-size: 32px auto; 
    width: 32px; 
    height: 32px; 
    cursor: move; 
} 

.drop-target { 
    background: whitesmoke url("http://i.imgur.com/uUvTRLx.png") repeat scroll 0 0/32px 32px; 
    border: 1px dashed orange; 
    height: 736px; 
    left: 0; 
    position: absolute; 
    top: 0; 
    width: 736px; 
} 

謝謝,任何幫助是極大的讚賞。

Toby。

回答

3

如果您願意修改可拖動的本身,我認爲它會使邏輯更易於應用。一旦拖動事件被觸發,你可以做很多事情,但是如果你修改可拖動的方法,你可以控制更多的控件。起初它看起來可能更復雜,但對於這種行爲,它有時更容易工作。

基本上,您可以在檢查網格和包容應用後運行您的isInPosition函數。通常下一步是設置新的位置,但是如果您的isInPosition返回true,則可以防止拖動。事情是這樣的:

'use strict' 
// This is the function generating the position by calculating 
// mouse position, different offsets and option. 

$.ui.draggable.prototype._generatePosition = function(event, constrainPosition) { 
    var containment, co, top, left, 
    o = this.options, 
    scrollIsRootNode = this._isRootNode(this.scrollParent[0]), 
    pageX = event.pageX, 
    pageY = event.pageY; 

    // Cache the scroll 
    if (!scrollIsRootNode || !this.offset.scroll) { 
    this.offset.scroll = { 
     top: this.scrollParent.scrollTop(), 
     left: this.scrollParent.scrollLeft() 
    }; 
    } 

    /* 
    * - Position constraining - 
    * Constrain the position to a mix of grid, containment. 
    */ 

    // If we are not dragging yet, we won't check for options 
    if (constrainPosition) { 

    if (this.containment) { 
     if (this.relativeContainer) { 
     co = this.relativeContainer.offset(); 
     containment = [ 
      this.containment[0] + co.left, 
      this.containment[1] + co.top, 
      this.containment[2] + co.left, 
      this.containment[3] + co.top 
     ]; 
     } else { 
     containment = this.containment; 
     } 

     if (event.pageX - this.offset.click.left < containment[0]) { 
     pageX = containment[0] + this.offset.click.left; 
     } 
     if (event.pageY - this.offset.click.top < containment[1]) { 
     pageY = containment[1] + this.offset.click.top; 
     } 
     if (event.pageX - this.offset.click.left > containment[2]) { 
     pageX = containment[2] + this.offset.click.left; 
     } 
     if (event.pageY - this.offset.click.top > containment[3]) { 
     pageY = containment[3] + this.offset.click.top; 
     } 
    } 

    if (o.grid) { 

     //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) 
     top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY)/o.grid[1]) * o.grid[1] : this.originalPageY; 
     pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 

     left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX)/o.grid[0]) * o.grid[0] : this.originalPageX; 
     pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 
    } 

    if (o.axis === "y") { 
     pageX = this.originalPageX; 
    } 

    if (o.axis === "x") { 
     pageY = this.originalPageY; 
    } 
    } 

// This is the only part added to the original function. 
// You have access to the updated position after it's been 
// updated through containment and grid, but before the 
// element is modified. 
// If there's an object in position, you prevent dragging. 

    if (isObjectInPosition(objects, [pageX - this.offset.click.left - this.offset.parent.left, pageY - this.offset.click.top - this.offset.parent.top])) { 
    return false; 

    } 

    return { 
    top: (
     pageY - // The absolute mouse position 
     this.offset.click.top - // Click offset (relative to the element) 
     this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent 
     this.offset.parent.top + // The offsetParent's offset without borders (offset + border) 
     (this.cssPosition === "fixed" ? -this.offset.scroll.top : (scrollIsRootNode ? 0 : this.offset.scroll.top)) 
    ), 
    left: (
     pageX - // The absolute mouse position 
     this.offset.click.left - // Click offset (relative to the element) 
     this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent 
     this.offset.parent.left + // The offsetParent's offset without borders (offset + border) 
     (this.cssPosition === "fixed" ? -this.offset.scroll.left : (scrollIsRootNode ? 0 : this.offset.scroll.left)) 
    ) 
    }; 

} 

var objects = [ 
    [0, 0], 
    [1, 1] 
]; 

$(function() { 
    $(".drag-item").draggable({ 
    grid: [32, 32], 
    containment: '.drop-target', 
    // on start you remove coordinate of dragged item 
    // else it'll check its own coordinates 
    start: function(event, obj) { 
     var objectId = $(this).attr('object-id'); 
     objects[objectId] = [null, null]; 
    }, 
    // on stop you update your array 
    stop: function(event, obj) { 
     var objectId = $(this).attr('object-id'); 
     var objectPositionX = $(this).position().left/32; 
     var objectPositionY = $(this).position().top/32; 
     objects[objectId] = [objectPositionX, objectPositionY]; 

    } 
    }); 
}); 


function isObjectInPosition(arrayToSearch, positionToFind) { 

    for (let i = 0; i < arrayToSearch.length; i++) { 
    if (arrayToSearch[i][0] === (positionToFind[0]/32) && arrayToSearch[i][1] === (positionToFind[1]/32)) { 

     return true; 
    } 
    } 
    return false; 
} 

https://jsfiddle.net/bfc4tsrh/1/

+0

非常感謝朱利安! –