【问题标题】:JQuery Draggable - Prevent grid objects from going in the same positionJQuery Draggable - 防止网格对象进入同一位置
【发布时间】:2016-03-05 21:49:30
【问题描述】:

我正在使用 JQuery Draggable 围绕网格移动项目。对象捕捉到 32x32 的网格区域。如果对象在同一位置,我希望能够取消网格捕捉。

拖动无法取消,只能阻止进入方格。在它被阻止并移回之前的位置之后,如果用户继续拖动到一个新的未占用的网格位置,它必须捕捉到那个位置。

我已经创建了一个演示,用于实现上述目的,但是 图像在尝试进入新位置时出现故障,但随后又被取消回到旧位置。

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

这是小提琴中的代码:

HTML:

   <div class="drop-target">
        <div class="drag-item" object-id="0"></div>
        <div class="drag-item" style="left: 32px;" object-id="1"></div>
    </div>

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;
}

谢谢,非常感谢您的帮助。

托比。

【问题讨论】:

    标签: javascript jquery jquery-ui jquery-draggable


    【解决方案1】:

    如果你愿意修改 draggable 本身,我认为它会使逻辑更容易应用。一旦触发了拖动事件,您可以做很多事情,但是如果您修改可拖动的 _generatePosition 方法,您将拥有更多的控制权。起初它可能看起来更复杂,但对于这种行为,它有时更容易工作。

    基本上,您可以在应用网格和包含检查后运行 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/

    【讨论】:

    • 非常感谢朱利安!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 2018-12-03
    • 2010-10-07
    • 1970-01-01
    相关资源
    最近更新 更多