将指针事件重新触发到下层(使用interact.js进行不规则形状的拖动)

时间:2016-03-15 23:13:03

标签: javascript jquery interact.js

我需要以一种可由任何相关事件处理程序(直接JS,jQuery或interact.js)处理的方式手动构造/触发mousedown事件,就像一个自然的mousedown事件一样。但是,事件似乎没有像我期望的那样触发任何事情。

我正在尝试使用interact.js库制作一些不规则形状的图像。图像只是具有透明部分的矩形img元素。在每个元素上,我定义了2个interact.js事件侦听器:

  1. 检查点击是否在图像区域内,如果没有则禁用拖动(触发“向下”事件)
  2. 处理拖动(触发“拖动”事件)
  3. 但是,如果img元素重叠,并且用户单击顶部元素的透明区域但是在下部元素的填充区域上,则下部元素应该是拖动的目标。尝试了几件事后(见下文),我已经解决了以下问题:在步骤1中禁用拖动的同时重新排序元素的z索引,然后在所有下层元素上重新触发mousedown事件。我正在使用“本机”事件类型(不是jQuery或interact.js),希望它只是复制原始的mousedown事件。

    // code to re-assign "zIndex"s
    function demote(element, interactible, event){
    
        // block dragging on element
        interactible.draggable(false);
    
        // get all images lower than the target 
        var z = element.css("zIndex");
        var images = $("img").filter(function() {
        return Number($(this).css("zIndex")) < z;
        });
    
        // push the target to the back
        element.css("zIndex",1);
    
        // re-process all lower events
        $(images).each( function () {
              // move element up
              $(this).css("zIndex",Number($(this).css("zIndex"))+1);
    
              // re-fire event if element began below current target
              elem = document.getElementById($(this).attr('id'));
    
              // Create the event.
              e = new MouseEvent("mousedown", {clientX: event.pageX, clientY: event.pageY});
              var cancelled = !elem.dispatchEvent(e);
        });
    }
    

    不幸的是,这不起作用,因为mousedown事件没有向任何处理程序注册。为什么呢?

    我在这个JSFiddle上有所有(相关)代码:https://jsfiddle.net/tfollo/xr27938a/10/ 请注意,这个JSFiddle看起来不像普通浏览器窗口那样流畅,但我认为它演示了预期的功能。

    我尝试过的其他事情:

    很多人提出了不同的方案来处理类似的问题(即将事件转发到较低层,使用指针事件:无等),但似乎都没有工作来触发interact.js处理程序并启动拖动交互正确的元素。我也尝试过使用interaction.start(由interact.js提供),但它似乎有问题 - 这个主题至少有一个未解决的问题,当我尝试在我选择的目标上开始一个新的拖动交互时,我得到了很多库中代码中的错误。

    我并不反对重新审视这些解决方案本身,但我也很想知道为什么手动触发mousedown事件将无效。

2 个答案:

答案 0 :(得分:1)

您是否尝试在较高级别设置css属性pointer-events: none(也可以通过javascript设置)?

答案 1 :(得分:1)

我们的想法是在父元素上监听down事件并选择手动拖动目标。此外,我没有使用z-index来选择要拖动的图像,因为z-index不适用于position:static。而不是我只是优先考虑图像,这完全取决于你。 https://jsfiddle.net/yevt/6wb5oxx3/3/

var dragTarget;

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;

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

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

function setDragTarget(event) {
  //choose element to drag
  dragTarget = $('#parent').find('img')
    .filter(function(i, el) {
      var clickCandicateRect = el.getBoundingClientRect();
      return insideBoundingRect(event.x, event.y, clickCandicateRect);
    }).sort(byPriority).get(0);
}

function insideBoundingRect(x, y, rect) {
  return (rect.left <= x) && (rect.top <= y) && (rect.right >= x) && (rect.bottom >= y);
}

function byPriority (a, b) {
  return $(b).data('priority') - $(a).data('priority');
}

function startDrag(event) {
  var interaction = event.interaction;
  var target = dragTarget;

  if (!interaction.interacting()) {
    interaction.start({ name: 'drag' }, event.interactable, target);
  }
}

//Give priority as you wish
$('#face1').data('priority', 2);
$('#face2').data('priority', 1);

interact('#parent').draggable({
  //use manualStart to determine which element to drag
  manualStart: true,
  onmove: dragMoveListener,
  restrict: {
    restriction: "parent",
    endOnly: true,
    elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
  },
})
.on('down', setDragTarget)
.on('move', startDrag);