2016-03-15 11 views
26

Potrzebuję ręcznie skonstruować/podpalić zdarzenie mousedown w sposób, który może być obsługiwany przez dowolne odpowiednie procedury obsługi zdarzeń (w prostym JS, jQuery lub interact.js), tak jak to bywało w przypadku mousedown. Wydarzenie nie wydaje się jednak powodować niczego tak, jak tego oczekuję.Ponowne uruchamianie zdarzeń wskaźnika na dolnej warstwie (w przypadku nieregularnego przeciągania za pomocą programu interact.js)

Próbuję przeciągnąć niektóre obrazy o nieregularnych kształtach za pomocą biblioteki interact.js. Obrazy są po prostu prostokątnymi elementami img z przezroczystymi częściami. Na każdym elemencie, mam zdefiniowane 2 interact.js detektory zdarzeń:

  1. sprawdzenie, czy kliknięcie było wewnątrz obszaru obrazu, wyłączenie przeciągnij czy też nie (pożary na zdarzenia „w dół”)
  2. Handling przeciągania (pożary w „przeciągania” zdarzenie)

Jeśli jednak IMG elementy nakładają się na siebie, a użytkownik kliknie w przezroczystym obszarze górnego elementu ale napełnionego obszarze dolnym elementu, dolnego elementu powinny być celem oporu. Po wypróbowaniu kilku rzeczy (patrz poniżej), zdecydowałem się na: ponowne zamawianie z-indeksów elementów w tym samym czasie, w którym wyłączam przeciąganie w kroku 1, a następnie ponowne uruchamianie mousedown zdarzenia na wszystkich niższych elementach . Używam "rodzimych" typów zdarzeń (nie jQuery lub interact.js) w nadziei, że dosłownie po prostu replikują pierwotne wydarzenie 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); 
    }); 
} 

Niestety, to nie działa, ponieważ zdarzenie mousedown nie rejestruje się w żadnej z procedur obsługi. Czemu?

mam wszystkie (istotne) kod na ten JSFiddle: https://jsfiddle.net/tfollo/xr27938a/10/ pamiętać, że ta JSFiddle nie wydają się działać tak sprawnie, jak ma to miejsce w normalnym oknie przeglądarki, ale myślę, że to pokazuje zamierzony funkcjonalności.

Inne rzeczy próbowałem:

Wiele osób zaproponowali różne systemy do obsługi podobne problemy (tzn spedycja zdarzenia do niższych warstw, przy użyciu wskaźnika-zdarzenia: Brak, itp), ale żaden nie wydają się działać na spuście interakcji interact.js i rozpocznij interakcję przeciągania w prawym elemencie. Próbowałem również using interaction.start (dostarczonego przez interakcję.js), ale wydaje się to błędne - istnieje co najmniej jeden otwarty problem na ten temat i kiedy próbowałem rozpocząć nową interakcję przeciągania na wybranym celu, dostałem dużo błędy z kodu biblioteki.

Nie jestem przeciwny ponownemu przeglądaniu żadnego z tych rozwiązań per se, ale chciałbym również wiedzieć, dlaczego ręczne uruchamianie mousedown zdarzenia nie będzie działać.

+0

Z której przeglądarki korzystasz? IE nie obsługuje konstruowania obiektów 'Event' - musisz użyć metod statycznych, takich jak' document.createEvent() 'lub coś podobnego. – TheHansinator

+0

Pracowałem w Chrome. Chciałbym jednak zmaksymalizować kompatybilność, więc spróbuję użyć funkcji createEvent(). – Tim

+2

MDN mówi, że createEvent() jest przestarzałe, a konstruktory zdarzeń (których używasz) są preferowaną metodą tworzenia obiektów zdarzeń. – TheHansinator

Odpowiedz

1

Chodzi o to, aby słuchać zdarzenia down na elemencie nadrzędnym i wybrać opcję ręcznego przeciągania. Również nie użyłem z-index do wyboru, który obraz przeciągnąć, ponieważ z-index nie działa z position:static. Zamiast tego po prostu dałem priorytety obrazom, to wszystko zależy od ciebie. 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); 
+1

+1 za używanie priorytetów. +2 do definiowania nowych zdarzeń/interakcji. Oba nowe dla mnie. Opierałem się dość mocno na bibliotece (ponieważ nie wiedziałem, jak to zrobić na własną rękę), ale myślę, że funkcjonalność, której szukam, jest trochę zbyt niestandardowa, więc myślę, że masz ogólny pomysł dobrze. – Tim

1

Czy próbowałeś ustawić właściwość css pointer-events: none na wyższych poziomach (może to być również ustawione przez javascript)?

+0

Tak, jednym z problemów jest to, że wszystkie początkowo dostępne elementy mogą być dostępne. Sprawdzam, aby upewnić się, że kliknięcie nastąpiło w prawidłowej (nieprzejrzystej) części obszaru elementu, a jeśli tak, to dobrze. Jeśli nie, dopiero wtedy chcę, aby interakcja przeszła do niższego elementu, jeśli istnieje (a następnie sprawdzona pod kątem tego elementu, itp.). Zmiana indeksu z i dodawanie "wskaźników-zdarzeń: brak" oboje kończą się niepowodzeniem, ponieważ po sprawdzeniu granic względem pierwszego elementu nie mogę ponownie uruchomić zdarzenia na sekundę. – Tim

Powiązane problemy