javascript - 使用 interact.js 拖放

标签 javascript jquery drag-and-drop rotation interact.js

我正在尝试构建一个允许在某些元素上调整大小/拖动和旋转的界面,为了实现这一点,我正在使用 interact.js javascript 库。

我的交互功能正常工作:

    interact('.resize-drag-ratio')
      .draggable({
        onmove: window.dragMoveListener
      })
      .resizable({
        preserveAspectRatio: true,
        edges: { left: true, right: true, bottom: true, top: true }
      })
      .on('resizemove', function (event) {
        var target = event.target,
            x = (parseFloat(target.getAttribute('data-x')) || 0),
            y = (parseFloat(target.getAttribute('data-y')) || 0);

        var min_size = 35;

        if(event.rect.width>min_size){
            // update the element's style
            target.style.width  = event.rect.width + 'px';
            target.style.height = event.rect.height + 'px';


            // translate when resizing from top or left edges
            x += event.deltaRect.left;
            y += event.deltaRect.top;

            target.style.webkitTransform = target.style.transform =
                'translate(' + x + 'px,' + y + 'px)';

            target.setAttribute('data-x', x);
            target.setAttribute('data-y', y);

            }
      });

和允许旋转的拖动旋转

    interact('.drag-rotate')
      .draggable({
      onstart: function (event) {
        const element = event.target;
        const rect = element.getBoundingClientRect();
        // store the center as the element has css `transform-origin: center center`
        element.dataset.centerX = rect.left + rect.width / 2;
        element.dataset.centerY = rect.top + rect.height / 2;

        console.log("element.dataset.centerX: "+element.dataset.centerX);
        console.log("element.dataset.centerY: "+element.dataset.centerY);

        // get the angle of the element when the drag starts
        element.dataset.angle = getDragAngle(event);
      },
      onmove: function (event) {
        var element = event.target;
        var center = {
          x: 300,
          y: 300,
        };

        console.log("element.dataset.centerX: "+element.dataset.centerX);
        console.log("element.dataset.centerY: "+element.dataset.centerY);

        var angle = getDragAngle(event);

        // update transform style on dragmove
      element.style.transform = 'rotate(' + angle + 'rad' + ')';
      },
      onend: function (event) {
        const element = event.target;

        // save the angle on dragend
        element.dataset.angle = getDragAngle(event);
      },
    })

这两个类使用 jQuery 进行切换,从而将拖动变为旋转,反之亦然。

我的问题是对象位置和旋转 Angular 没有保持原样,我不确定如何解决。

在我将一个元素拖到某个位置并按下旋转按钮后,我开始旋转它移动到顶部:0px 左侧:0px 并且不会停留在其拖动位置的元素。

你可以在这里看到完整的工作代码: https://codepen.io/yaary-vidanpeled/pen/ZZwGmE

最佳答案

问题:

发生这种情况是因为每次应用 css 时,您都会覆盖以前的样式。

这是一个例子,假设您有一个文本(#text 元素),其colorred,现在您想更改它与 JavaScript。

document.getElementById('text').style.color = 'green';

这里到底发生了什么?被指定为样式对象的颜色属性的任何内容现在都被覆盖了。

当您编写时(在您对 .resize-drag-ratio 的交互初始化中)也会发生同样的事情:

target.style.transform = 'translate(' + x + 'px,' + y + 'px)';

然后通过编写再次覆盖translate(在.drag-rotate 的交互初始化中)

element.style.transform = 'rotate(' + angle + 'rad' + ')';

请记住 rotate()translate() 都是css translate 属性的值。

解决方案:

你应该以某种方式保留所有这些旋转 Angular ,并转换值。 (看起来您已经为它们设置了data-attribtues,所以不会很难)

并应用 element.style.transform 的值如下:

target.style.transform = 'translate(' + x + 'px,' + y + 'px) rotate(' + angle + 'rad)';

注意:您的代码段有 function dragMoveListener(event) { 声明了两次。

工作片段:

console.log('start');

//function isEven
function isEven(n) {
  return n == parseFloat(n) ? !(n % 2) : void 0;
}


interact('.resize-drag-ratio')
  .draggable({
    onmove: window.dragMoveListener
  })
  .resizable({
    preserveAspectRatio: true,
    edges: {
      left: true,
      right: true,
      bottom: true,
      top: true
    }
  })
  .on('resizemove', function(event) {
    var target = event.target,
      x = (parseFloat(target.getAttribute('data-x')) || 0),
      y = (parseFloat(target.getAttribute('data-y')) || 0);

    rotation = (parseFloat(target.getAttribute('data-angle')) || 0)

    var min_size = 35;

    if (event.rect.width > min_size) {
      // update the element's style
      target.style.width = event.rect.width + 'px';
      target.style.height = event.rect.height + 'px';


      // translate when resizing from top or left edges
      x += event.deltaRect.left;
      y += event.deltaRect.top;

      target.style.webkitTransform = target.style.transform =
        'translate(' + x + 'px,' + y + 'px) rotate(' + rotation + 'rad)';

      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);

    }
  });


interact('.resize-drag')
  .draggable({
    onmove: window.dragMoveListener
  })
  .resizable({
    preserveAspectRatio: false,
    edges: {
      left: true,
      right: true,
      bottom: true,
      top: true
    }
  })
  .on('resizemove', function(event) {
    var target = event.target,
      x = (parseFloat(target.getAttribute('data-x')) || 0),
      y = (parseFloat(target.getAttribute('data-y')) || 0),

      rotation = (parseFloat(target.getAttribute('data-angle')) || 0)

    //console.log("event.rect.width: "+event.rect.width);

    //prevents resizing to units smaller then 35px
    var min_size = 35;

    if (event.rect.width > min_size) {
      // update the element's style
      target.style.width = event.rect.width + 'px';
      target.style.height = event.rect.height + 'px';

      //$("#form_bubble_width").val(event.rect.width);
      //$("#form_bubble_width").val(event.rect.height);

      // translate when resizing from top or left edges
      x += event.deltaRect.left;
      y += event.deltaRect.top;

      target.style.webkitTransform = target.style.transform =
        'translate(' + x + 'px,' + y + 'px) rotate(' + rotation + 'rad)';

      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);
      //target.textContent = event.rect.width + '×' + event.rect.height;
    }
  });




// target elements with the "draggable" class
interact('.draggable')
  .draggable({
    // enable inertial throwing
    inertia: true,
    // keep the element within the area of it's parent
    restrict: {
      restriction: "parent",
      endOnly: true,
      elementRect: {
        top: 0,
        left: 0,
        bottom: 1,
        right: 1
      }
    },
    // enable autoScroll
    autoScroll: true,

    // call this function on every dragmove event
    onmove: dragMoveListener,
    // call this function on every dragend event
    onend: function(event) {

      // var textEl = event.target.querySelector('p');

      console.log(event.target.id)

      var distance = (Math.sqrt(Math.pow(event.pageX - event.x0, 2) +
          Math.pow(event.pageY - event.y0, 2) | 0))
        .toFixed(2) + 'px';

    }

  });


interact('.resize-drag , .resize-drag-ratio').on('tap', function(event) {
  event.preventDefault();
  var target = event.target
  console.log("tap resize-drag class element");

  var uuid = target.id;
  //console.log("uuid: "+uuid);
  console.log("click");
});


function dragMoveListener(event) {
  var target = event.target,
    // keep the dragged position in the data-x/data-y attributes
    x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
    y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy,

    rotation = (parseFloat(target.getAttribute('data-angle')) || 0);

  // translate the element
  target.style.webkitTransform =
    target.style.transform =
    'translate(' + x + 'px, ' + y + 'px) rotate(' + rotation + 'rad)';

  // update the posiion attributes
  target.setAttribute('data-x', x);
  target.setAttribute('data-y', y);
  target.setAttribute('data-angle', rotation);
}

// this is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener;


var mouseX = 0,
  mouseY = 0


//function onMousemove(e)
function onMousemove(e) {
  var m_posx = 0,
    m_posy = 0,
    e_posx = 0,
    e_posy = 0,
    obj = this;
  //get mouse position on document crossbrowser
  if (!e) {
    e = window.event;
  }
  if (e.pageX || e.pageY) {
    m_posx = e.pageX;
    m_posy = e.pageY;
  } else if (e.clientX || e.clientY) {
    m_posx = e.clientX + document.body.scrollLeft +
      document.documentElement.scrollLeft;
    m_posy = e.clientY + document.body.scrollTop +
      document.documentElement.scrollTop;
  }
  //get parent element position in document
  if (obj.offsetParent) {
    do {
      e_posx += obj.offsetLeft;
      e_posy += obj.offsetTop;
    } while (obj = obj.offsetParent);
  }
  // mouse position minus elm position is mouseposition relative to element:
  dbg.innerHTML = ' X Position: ' + (m_posx - e_posx) +
    ' Y Position: ' + (m_posy - e_posy);

  mouseX = (m_posx - e_posx);
  mouseY = (m_posy - e_posy);

}

var elem = document.getElementById('container');
//elem.addEventListener('mousemove', onMousemove, false);

var dbg = document.getElementById('dbg'); //just for debug div instead of console

$(document).ready(function() {
  var is_rotate = true;

  $("#btn_rotate").click(function() {
    // console.log('ddd');
    if (is_rotate) {
      $(this).text('drag-resize');
      $(".element").removeClass("drag-rotate");
      $(".element").addClass("resize-drag-ratio");
      is_rotate = false;
    } else {
      $(this).text('rotate');
      $(".element").removeClass("resize-drag-ratio");
      $(".element").addClass("drag-rotate");
      is_rotate = true;
    }
    //console.log('click: '+is_rotate);

  });


  var saved_mouseX = 0;
  var saved_mouseY = 0;

  //interact("#container").on('tap', function (event) {
  interact("#container").on('tap', function(event) {
    event.preventDefault();
    var target = event.target
    if (target.id == "tp_image") {
      console.log(target.id);
      console.log(mouseX + "-" + mouseY);

      saved_mouseX = mouseX;
      saved_mouseY = mouseY;

      //$('#modal_stickers').modal('show');
    }
  });


  //interact('.drag-rotate')
  interact('.drag-rotate')
    .draggable({
      onstart: function(event) {
        const element = event.target;
        const rect = element.getBoundingClientRect();
        // store the center as the element has css `transform-origin: center center`
        element.dataset.centerX = rect.left + rect.width / 2;
        element.dataset.centerY = rect.top + rect.height / 2;

        // console.log("element.dataset.centerX: " + element.dataset.centerX);
        // console.log("element.dataset.centerY: " + element.dataset.centerY);

        // get the angle of the element when the drag starts
        element.dataset.angle = getDragAngle(event);
      },
      onmove: function(event) {
        var element = event.target;

        var center = {
          x: 300,
          y: 300,
        };

        // console.log("element.dataset.centerX: " + element.dataset.centerX);
        // console.log("element.dataset.centerY: " + element.dataset.centerY);

        var angle = getDragAngle(event);
        var x = element.dataset.x;
        var y = element.dataset.y;

        // update transform style on dragmove
        // this is where the bug was; at initial point, there was no x, or y position set on the dataset of the element. thus your style value would be undefined, so here we check the values of x and y first and set the style accordingly;
        if (typeof x != 'undefined' && typeof y != 'undefined') {
          element.style.transform = 'translate(' + x + 'px, ' + y + 'px) rotate(' + angle + 'rad' + ')';
        } else {
          element.style.transform = 'rotate(' + angle + 'rad' + ')';
        }

      },
      onend: function(event) {
        const element = event.target;

        // save the angle on dragend
        element.dataset.angle = getDragAngle(event);
      },
    })


  //function getDragAngle(event)
  function getDragAngle(event) {
    var element = event.target;
    var startAngle = parseFloat(element.dataset.angle) || 0;
    var center = {
      x: parseFloat(element.dataset.centerX) || 0,
      y: parseFloat(element.dataset.centerY) || 0,
    };
    var angle = Math.atan2(center.y - event.clientY,
      center.x - event.clientX);

    return angle - startAngle;
  }

});
#btn_rotate {
  position: absolute;
  top: 0;
  left: 0;
  cursor: pointer;
  background: #ccc;
  padding: 30px;
}

.element {
  width: 25%;
  min-height: 6.5em;
  margin: 10%;
  background-color: #29e;
  color: white;
  /* added later */
  touch-action: none;
  box-sizing: border-box;
}
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.0.js"></script>
<script type="text/javascript" src="https://unpkg.com/interactjs@next/dist/interact.js"></script>




<div class="element drag-rotate">
  <p> drag to rotate</p>
</div>

<div id="btn_rotate">rotate
</div>

检查脚本部分的第 288 行。有一条评论解释了 if block 以及发生这种情况的原因。

关于javascript - 使用 interact.js 拖放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55869080/

相关文章:

javascript - 在iron.io中运行casperjs时权限被拒绝

javascript - 为什么显示/隐藏密码仅适用于一个输入字段

javascript - 如何让 fullcalendar 进行两次选择?

c++ - Qt 删除一个文件 |苹果系统

javascript - 从网格拖放到树上,无需添加树节点

javascript - Javascript 图像轮播上的手动控件(上一个和下一个)

javascript - 如何找到不比选择器更深的元素?

javascript - 当ID选择器缓存在jquery中时,ID选择器是否比类选择器快

jquery - 滑动 DIV 的快速 JQuery 问题

jquery - 将两个图像绑定(bind)在一起以进行拖动