Подтвердить что ты не робот

Переустановка событий указателя на нижний слой (для перетаскивания неправильной формы с помощью взаимодействия .js)

Мне нужно вручную создать/запустить событие mousedown таким образом, чтобы его можно было обрабатывать любыми релевантными обработчиками событий (прямо в JS, jQuery или interactive.js), как и в случае с естественным событием mousedown. Однако событие, похоже, не вызывает ничего, что я ожидаю.

Я пытаюсь сделать некоторые изображения неправильной формы, перетаскиваемые с помощью библиотеки interactive.js. Изображения представляют собой просто прямоугольные элементы img с прозрачными частями. На каждом элементе я определил 2 event.js прослушивателя событий:

  • Проверка наличия щелчка внутри области изображения, отключение перетаскивания, если нет (срабатывает событие "вниз" )
  • Обработка перетаскивания (срабатывает при перетаскивании)

Однако, если элементы img перекрываются, и пользователь щелкает в прозрачной области верхнего элемента, но на заполненной области нижнего элемента нижний элемент должен быть целью перетаскивания. Попробовав несколько вещей (см. Ниже), я решил решить следующее: переупорядочить z-индексы элементов одновременно с отключением перетаскивания на шаге 1, а затем повторно запустить событие mousedown на всех нижних элементах, Я использую "родной" тип события (не jQuery или interactive.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 не работает так гладко, как в обычном окне браузера, но я думаю, что он демонстрирует предполагаемую функциональность.

Другие вещи, которые я пробовал:

Множество людей предложили разные схемы для решения аналогичных задач (например, пересылка событий на более низкие уровни с использованием указателей-событий: нет и т.д.), но ни один из них не работает для запуска обработчика interactive.js и запускает взаимодействие перетаскивания на правый элемент. Я также пробовал использовать interactive.start(предоставлено interactive.js), но он кажется ошибочным - в этой теме есть хотя бы одна открытая проблема, и когда я попытался начать новое взаимодействие с перетаскиванием по цели по своему выбору, я получил много ошибок из кода библиотеки.

Я не против пересмотра каких-либо из этих решений как таковых, но мне также очень хотелось бы знать, почему ручной запуск события mousedown не будет работать.

4b9b3361

Ответ 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);

Ответ 2

Вы пытались установить свойство css pointer-events: none на более высоких уровнях (его также можно установить с помощью javascript)?