【问题标题】:Snap to parent grid on start of drag在拖动开始时捕捉到父网格
【发布时间】:2015-05-26 22:35:26
【问题描述】:

我对 JavaScript 和 JQuery 还很陌生,如果我遗漏了一两个技巧,敬请见谅。

我已经弄清楚如何让 JQuery UI 可拖动对象使用网格选项,并且在页面加载后,“捕捉到所有可拖动对象都引用的虚构网格”(在代码 cmets 中解释)。但是,我不知道如何让这种行为发生.on("dragstart")

HTML:

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <script type="text/javascript" src="jquery-1.10.2.js"></script>
  <script type="text/javascript" src="jquery-ui.js"></script>
  <script type="text/javascript" src="dragger.js"></script>
</head>

<body>
  <div id="parent">
    <svg width="300" height="100" class="draggable" id="number1">
      <rect x="0" y="0" rx="10" ry="10" width="300" height="100" style="fill:rgb(121,0,121);stroke-width:3;stroke:rgb(0,0,0);">
    </svg>
    <svg width="300" height="100" class="draggable" id="letterA">
      <rect x="0" y="0" rx="100" ry="10" width="300" height="100" style="fill:rgb(0,121,121);stroke-width:3;stroke:rgb(255,0,0);">
    </svg>
  </div>
</body>

</html>

注意: 两个矩形之间有一个白色的间隙,通过下面的第二个 JavaScript,一旦块被捕捉到网格,它就会消失。或者,这 2 个矩形应该可以相互拖动,并且彼此齐平排列,以被视为对齐到网格上。

JavaScript (dragger.js):

var roundedRemainder = function(numer, denom) {
  return numer - (Math.round(numer / denom) * denom);
}

var snapPosition = function(obj, granularity) {
  obj.position({
    my: "left top", // Unchanging reference point on draggable object
    at: "left top", // Unchanging reference point on reference object
    of: "#parent",  // The object that you want to move items with respect to.
    using: function(position, data) {
      var newPositions = {
          // Get the difference between the "imaginary grid" and the current grid
          left: function() {
            return roundedRemainder(position.left, granularity);
          },
          top: function() {
            return roundedRemainder(position.top, granularity);
          }
        }
        // Move to the imaginary grid
      $(this).css(newPositions);
      return newPositions;
    }
  });
}

$(function() {
  var gridSize = 50;
  $(".draggable")
    // Enable grid usage
    .draggable({
      grid: [gridSize, gridSize]
    })
    .on("dragstart", function(event, ui) {
      var newPos = snapPosition(ui.helper, gridSize);
    })
});

证明snapPosition中的代码有效:

var roundedRemainder = function(numer, denom) {
  return numer - (Math.round(numer / denom) * denom);
}

$(function() {
  var gridSize = 50;
  $(".draggable")
    // Enable grid usage
    .draggable({
      grid: [gridSize, gridSize]
    })
    .position({
      my: "left top", // Unchanging reference point on draggable object
      at: "left top", // Unchanging reference point on reference object
      of: "#parent", // The object that you want to move items with respect to.
      using: function(position, data) {
        var newPositions = {
            // Get the difference between the "imaginary grid" and the current grid
            left: function() {
              return roundedRemainder(position.left, granularity);
            },
            top: function() {
              return roundedRemainder(position.top, granularity);
            }
          }
          // Move to the imaginary grid
        $(this).css(newPositions);
      }
    })
});

第一个 JavaScript 尝试在拖动开始后更改块的位置,以将其对齐到假想的网格。第二个在加载页面时自动执行此操作,但不会再执行此操作。例如,如果我将虚构的网格粒度从 50 更改为 79,则拖动不会将对象带回所需的网格。

有没有什么地方可以让我学习如何做到这一点?可行吗?

澄清一下:

  • JQuery = 1.10.2(与 JQuery UI 演示中的相同)
  • JQuery UI = 1.11.4(与 JQuery UI 演示中的相同)
  • 浏览器 = Ubuntu 14.04 上的 Firefox,一切都是最新的

我已经使用过 Google,但是类似于“开始”、“拖动”和“位置”的术语不够独特,无法缩小范围,或者我没有找到合适的位置。我还浏览了 JQuery (UI) 档案。

非常感谢!

【问题讨论】:

    标签: javascript jquery html jquery-ui draggable


    【解决方案1】:

    好的,事实证明有几个代表我无知的例子。我将在下面通过它们来帮助其他人,但如果你只是在寻求解决方案,那就不要再看了:

    var roundedRemainder = function(numer, denom) {
      if (denom > 1) // Only calculate when there is a chance the draggable isn't on the grid.
        return numer - (Math.round(numer / denom) * denom); // Note: denom = 0 is invalid.
      else
        return 0; // If denom is invalid, or 1, then assume the draggable is on the grid.
    }
    
    $(function() {
      var gridSize = 79;
      var _this = this;
      $(".draggable")
        .draggable({
          // Enable grid constraints
          grid: [gridSize, gridSize],
    
          // At start of dragging (aka, only do once at the beginning)
          // snap the draggable object onto its parents grid.
          drag: function(event, ui) {
            var gridOffsetLeft;
            var gridOffsetTop;
            ui.helper.position({
              my: "left top", // For the top left of the draggable object
              at: "left top", // Link to the top left of the reference object
              of: $(this).parent(), // Make the reference object the parent of the draggable object
              // Calculate the grid offset from where the object ORIGINATED from
              using: function(position, data) {
                gridOffsetLeft = roundedRemainder(position.left, gridSize);
                gridOffsetTop = roundedRemainder(position.top, gridSize);
              }
            });
            // Calculate the total offset based off of the current
            // location of the draggable object, and the previously
            // calculated offset.
            gridOffsetLeft -= roundedRemainder(ui.position.left, gridSize);
            gridOffsetTop -= roundedRemainder(ui.position.top, gridSize);
    
            // Apply offsets & hence snap the draggable onto the
            // parents grid.
            ui.position.left += gridOffsetLeft;
            ui.position.top += gridOffsetTop;
          }
        })
    });
    <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8" />
      <script type="text/javascript" src="jquery-1.10.2.js"></script>
      <script type="text/javascript" src="jquery-ui.js"></script>
      <script type="text/javascript" src="dragger.js"></script>
    </head>
    
    <body>
      <div id="parent">
        <svg width="300" height="100" class="draggable" id="number1">
          <rect x="0" y="0" rx="10" ry="10" width="300" height="100" style="fill:rgb(121,0,121);stroke-width:3;stroke:rgb(0,0,0);">
        </svg>
        <svg width="300" height="100" class="draggable" id="letterA">
          <rect x="0" y="0" rx="100" ry="10" width="300" height="100" style="fill:rgb(0,121,121);stroke-width:3;stroke:rgb(255,0,0);">
        </svg>
      </div>
    </body>
    
    </html>

    错误:

    1. 第一个错误是我试图将定位功能与拖动功能分开的方式。具体来说,当尝试发送then 时。我还没有真正理解这一点,这就是为什么它不在解决方案中,但是我确实阅读(并丢失了链接)使用var _then = then; 或使用绑定方法提到的堆栈溢出。如果我找到链接,我会编辑答案。
    2. 下一个错误与我的“开始时”规范有关。我想要一种仅在每次拖动开始时捕捉到父网格的方法。因此,根据文档,使用start:.on("dragstart", ...) 功能听起来合乎逻辑。这会导致preventDefault 问题,即忽略启动命令,因此没有捕捉,但我可以拖动,或者如果我在开始时使用event.preventDefault,它会捕捉但不再拖动。原来drag: 功能仅在拖动开始时运行一次(如果我错了,请纠正我)。通过将捕捉功能放回原处,解决了另一个错误。
    3. 最后,我原来的捕捉到网格的逻辑是错误的。只使用一次它就可以工作,但是一旦每次拖动对象时运行它,每次拖动它都会“爬行”一点。这是因为“捕捉”功能从拖动对象的 ORIGINAL 位置到父对象。因此,每次仅添加该差异,即使对象已经被捕捉,也会导致错误。为了解决这个问题,我简单地将对象的 originalcurrent 位置的差异,到以 original 位置为中心的相同网格对象。

    (要清楚,有 3 个参考位置,、被拖动对象的原始位置和当前位置被拖动的对象)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-08
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 2020-12-20
      • 1970-01-01
      相关资源
      最近更新 更多