Drag / Drop Conflict with Hammer.JS and jQuery UI + Punch



  • So I am working up an example for a client to convert their prior web application which was done in Flex / Flash to a HTML5 mobile / tablet app. This app relies extensively on drag / drop behaviors for sorting images. I originally was going to use gesture detector but saw that it would be too difficult to move the images around the screen by changing the x y coordinates onend.

    This brought me to use jQueryui + punch and I have it working great except for the moment I add onsenui.js, it all fails. I believe this to be because Hammer.JS is conflicting with jQueryUI. Is this correct?

    If so, is it possible to prevent this OR is there a better all Onsen way of doing this? Based on previous discussions, I would believe not at the moment.

    Edit: I should also add, that maybe I am not doing the gesture detector correctly. Upon drag, the image never moved, but the event returned where I started the drag and where I ended the drag. I assumed, I would then just change the position of the image to the end coordinates. With the other framework, I do not have to code this as it is automatically done.

    Edit2: In sticking with the gesture detector, I was trying to do this:

    var el = document.getElementById("img1");
    el.addEventListener("dragend", function(e) {
          console.log(JSON.stringify(e));
          el.style.left = e.gesture.pageX;
          el.style.top = e.gesture.pageY;
    });  
    

    However, it never moved and the other available coordinates did not seem to be relevant.

    Edit2: I have attempted to implement everything listed here: https://community.onsen.io/topic/325/problems-in-drag-drop-while-moving-to-onsen-2/25 without success as well. I guess my big question is, how to access Hammer.JS. I have tried new Hammer(...) which results in an error of Hammer is undefined.


  • Onsen UI

    @munsterlander We call it GestureDetector instead of hammer, and I think we don’t attach it to window. It should be available in ons.GestureDetector I think.

    I think you should use drag event instead of dragend. Also, el.style.left should be a string ended in “px”. A number doesn’t work. I made something quick here, I guess you can make something better from there :)

    Otherwise, did you try document.body._gestureDetector.dispose() to remove it?



  • @Fran-Diox I had tried dispose(), using px, and the drag event; however, I think I wasn’t grabbing the right information. I had dumped the event object but never latched on to the srcEvent.movementX for the coordinates as I was trying clientX and pageX based on the Hammer documentation that I had found (may have been outdated.)

    Thanks for the quick codepen! I will most definitely be able to use this to get everything going!



  • @Fran-Diox:

    Interesting that your codepen works in preview but not in the debugger on the device. I am perplexed as I can’t seem to get the event listener to register. I even wrapped it in a gesture detector but nothing on mobile - again, works great on desktop. Regardless, I will have to move on from this one for a bit. Other projects are calling.


  • Onsen UI

    @munsterlander Maybe the events are different since in the phone you are tapping and not clicking?

    – Yes, I just checked the previous codepen with Chrome Dev Tools (it simulates tapping) and it doesn’t move :sweat_smile:
    I guess we would need to check the event object for tapping.



  • @Fran-Diox I have been working on this again and have it working on mobile, it has to do with movementX not being defined for the event. So, I have been looking at what is returned by the event. Here is a partial event dump:

    {"isTrusted":false,"gesture":{"center":{"pageX":55,"pageY":115,"clientX":55,"clientY":115},"timeStamp":1474597390539,"target":{},"touches":[{"isTrusted":true,"identifier":1}],"eventType":"move","pointerType":"mouse","srcEvent":{"isTrusted":true,"identifier":1},"velocityX":0,"velocityY":0.015748031496062992,"interimAngle":90,"interimDirection":"down","startEvent":{"center":{"pageX":55,"pageY":115,"clientX":55,"clientY":115},"timeStamp":1474597390265,"target":{},"touches":[{"clientX":55,"clientY":105}],"eventType":"start","pointerType":"mouse","srcEvent":{"isTrusted":true,"identifier":1}},"deltaTime":274,"deltaX":0,"deltaY":0,"distance":0,"angle":0,"direction":"right","scale":1,"rotation":0}}
    

    Any thoughts?

    Edit: Ok, so totally sorry for the numerous edits here, but I am rubber ducking this. I grabbed deltaX and it works awesome for the first time you move it. Once you try to move it again, it resets to the top of the page. So I did your logic with parseInt, however, the div shot all around the screen so. Anyway, this is working (just got to get it to save its location) - almost there!

    e.target.style.top = e.gesture.deltaY + 'px';
    e.target.style.left = e.gesture.deltaX + 'px';
    


  • @Fran-Diox I finally got this working and it is so unique I am going to do a tutorial on multiple drag and drop elements for gaming with Onsen UI. Quick question though, if I use the splitter component like in the other thread, drag stops due to the hammer conflict in components. So, I have tried the following as well but without luck. Do you have to enable the gesture detector on the draggable items as the event listener comes after the dispose?

    document.body._gestureDetector.dispose();
    document.getElementById('menu')._gestureDetector.dispose();
    

    Edit: I realized that this code was for v1 and have since corrected this. I have it working with the splitter initially. Once you open the menu and select an item, then the drag stops working. I have tried adding an event listener for show which then recalls the dispose method but that isn’t working.

    EDIT 2 - SOLVED!!! I wasn’t watching and my show event listener was in my ons.ready() function. Once outside, everything works great! Stand by for a github tutorial on this, because this one has taken me about 2 weeks to perfect.


  • Onsen UI

    @munsterlander Hey! I’m finally back in Tokyo after a long trip. I didn’t have much time to check these issues but I’m glad you could figure it out! I’m updating now the tutorial app for Angular2 support. If you want to make an example about this for vanilla or anything it would be awesome. Thanks!



  • @Fran-Diox No problem at all! I am most definitely going to be adding / creating a tutorial about this as in retrospect, it isn’t that complex, but wow did it take me awhile going through onsen and hammer source code plus with a custom dump function before I finally realized what was going on. In short, to get this working perfectly you need ondragstart, drag, and ondragend. To get it to work with splitter you need:

    window.fn.disableGD = function(){
       var vGD = ons.GestureDetector(document.getElementById('menu'));
       vGD.dispose(); 
    }
    

    This is called on page show. The code overall is very minimal too!



  • @Fran-Diox As stated, here is the tutorial for everyone: https://github.com/munsterlander/Onsen-Examples/tree/master/Draggable-Items

    Let me know if it is something you want to PR or if you think I should tweak it. Comments are appreciated!


  • Onsen UI

    @munsterlander Thanks! Have you seen this contest? I think you can submit that repo :smiley:



  • @Fran-Diox Thanks! I did submit it so now I just need those votes and shares!

    Edit: On Reddit: https://www.reddit.com/r/javascript/comments/55xbgi/multiple_item_drag_and_drop_and_the_splitter/

    Edit2: I know some might say, but wait, just use this in the drag event:

    e.target.style.transform = 'translate(' + e.gesture.deltaX + 'px,' + e.gesture.deltaY + 'px)';
    

    The reason I did not, is due to when the object is dropped then picked up again, it causes the object to always jump back about 100 px top and left, so it creates a wonky interface.