Drag-and-drop code does not work with hammer.js

I have successfully implemented jQueryUI draggable, but as soon as I add the hammer.js code, the drag and drop code no longer works.

This is not the case as soon as I turn on hammer.js, but as soon as I use the script.

Why is this? How can I make them both work?

Both draggable and hammer apply to .dataCard and #main

Drag-and-drop code works fine here (with a Hammer implementation record): http://goo.gl/MO5Pde

Here is an example of draggable code:

 $('#main').draggable({ axis:'y', revert:true, start: function(event, ui){ topValue = ui.position.top; }, drag: function(event, ui){ if(pastBreakpoint === false){ $('#searchInput').blur(); if(topValue > ui.position.top) return false; if(ui.position.top >= 161){ if(pastBreakpoint === false){ pastBreakpoint = true; if($('.loadingRefresh').length === 0) $('#main').before('<div class="loadingRefresh"></div>'); else{ $('.loadingRefresh').remove(); $('#main').before('<div class="loadingRefresh"></div>'); } $('.loadingRefresh').fadeIn(); $('#main').mouseup(); setTimeout(function(){ location.reload(); }, 1000); } } } } }); 

Here is the hammer code without commenting, and the drag and drop code does not work: http://goo.gl/994pxF

Here is the hammer code:

 var hammertime = Hammer(document.getElementById('main'), { transform_always_block: true, transform_min_scale: 0 }); var posX = 0, posY = 0, lastPosX = 0, lastPosY = 0, bufferX = 0, bufferY = 0, scale = 1, last_scale = 1; hammertime.on('touch transform transformend', function(ev) { if ((" " + ev.target.className + " ").indexOf(" dataCard ") < 0) return; else manageMultitouch(ev, ev.target); }); function manageMultitouch(ev, element) { switch (ev.type) { case 'touch': last_scale = scale; return; case 'transform': scale = Math.min(last_scale * ev.gesture.scale, 10); break; } if(scale <= 0.5) $(element).hide('clip'); if(scale > 1.0) $(element).addClass('focused'); var transform = "translate(" + 0 + "px," + 0 + "px) " + "scale(" + 1 + "," + scale + ")"; var style = element.style; style.transform = transform; style.oTransform = transform; style.msTransform = transform; style.mozTransform = transform; style.webkitTransform = transform; } 
+7
javascript jquery jquery-ui jquery-ui-draggable
source share
3 answers

I had the same problem in my application, even with the touch point enabled. I had to do some good research to find out what the problem with jquery ui overloading is. The emerging issue is the Default warning set in the event (only when the hammer is turned on), changing the result of the trigger method from jquery ui.

Ok, let's go back a bit: The first method you should see is _mouseMove() , associated with the mousemove event. Drag and drop will only be performed when the condition (this._mouseStart(this._mouseDownEvent, event) !== false) is true.

 _mouseMove: function (event) { // IE mouseup check - mouseup happened when mouse was out of window if ($.ui.ie && (!document.documentMode || document.documentMode < 9) && !event.button) { return this._mouseUp(event); } if (this._mouseStarted) { this._mouseDrag(event); return event.preventDefault(); } if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { this._mouseStarted = (this._mouseStart(this._mouseDownEvent, event) !== false); (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); } return !this._mouseStarted; } 

The following method will create a helper (clone of the element), set some css in the element and return true (the expected value) if this._trigger("start", event) does not return false.

 _mouseStart: function(event) { var o = this.options; //Create and append the visible helper this.helper = this._createHelper(event); this.helper.addClass("ui-draggable-dragging"); //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable if($.ui.ddmanager) { $.ui.ddmanager.current = this; } /* * - Position generation - * This block generates everything position related - it the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Store the helper css position this.cssPosition = this.helper.css( "position" ); this.scrollParent = this.helper.scrollParent(); this.offsetParent = this.helper.offsetParent(); this.offsetParentCssPosition = this.offsetParent.css( "position" ); //The element absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset(); this.offset = { top: this.offset.top - this.margins.top, left: this.offset.left - this.margins.left }; //Reset scroll cache this.offset.scroll = false; $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }, parent: this._getParentOffset(), relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper }); //Generate the original position this.originalPosition = this.position = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options this._setContainment(); //Trigger event + callbacks if(this._trigger("start", event) === false) { this._clear(); return false; } //Recache the helper size this._cacheHelperProportions(); //Prepare the droppable offsets if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); } this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) if ( $.ui.ddmanager ) { $.ui.ddmanager.dragStart(this, event); } return true; } 

Below is the first trigger called, its view from the widget.

 _trigger: function (type, event, ui) { ui = ui || this._uiHash(); $.ui.plugin.call(this, type, [event, ui]); //The absolute position has to be recalculated after plugins if(type === "drag") { this.positionAbs = this._convertPositionTo("absolute"); } return $.Widget.prototype._trigger.call(this, type, event, ui); } 

At this point, the result will call another trigger method (this time from $ .Widget) and the point at which we have a problem.

  _trigger: function (type, event, data) { var prop, orig, callback = this.options[type]; data = data || {}; event = $.Event(event); event.type = (type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type).toLowerCase(); // the original event may come from any element // so we need to reset the target on the new event event.target = this.element[0]; // copy original event properties over to the new event orig = event.originalEvent; if (orig) { for (prop in orig) { if (!(prop in event)) { event[prop] = orig[prop]; } } } return !($.isFunction(callback) && callback.apply(this.element[0], [event].concat(data)) === false || event.isDefaultPrevented()); } return !($.isFunction(callback) && callback.apply(this.element[0], [event].concat(data)) === false || event.isDefaultPrevented()); 

Our problem is in this line. More specifically || before event.isDefaultPrevented() . When the hammer is turned on, the event.isDefaultPrevented() method returns true, after the value is rejected before returning, the final value will be false. (Without a hammer, the included event.isDefaultPrevented() returns false as expected.) After backing up our _moseMouve() , instead of calling the _mouseDrag() method, it will call _mouseUp() . U can see that it will cancel events and call _mouseStop() .

 _mouseUp: function (event) { $(document) .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); if (this._mouseStarted) { this._mouseStarted = false; if (event.target === this._mouseDownEvent.target) { $.data(event.target, this.widgetName + ".preventClickEvent", true); } this._mouseStop(event); } return false; } 

If you change the OR (||) operator with AND (& &), it will work fine. Of course, this is not a small change, I tested it, and until that moment I did not find any problems. The line will be like this:

 return !($.isFunction(callback) && callback.apply(this.element[0], [event].concat(data)) === false && event.isDefaultPrevented()); 

As I said, it is not 100% safe, but so far I have not found a reason to save || instead of & &. I will check it for a few days. In addition, I already sent an email to the lead developer from jquery ui asking about it.

+3
source share

A similar problem for me using isomorphic smartclient.

I fixed this by handling the start event and resetting isDefaultPrevented to false

 $(element).draggable({ start: function (event, ui) { event.isDefaultPrevented = function () { return false; } } }); 
+1
source share

I had the same problem and I found this problem on github .

The solution shown using event delegation worked fine for me:

 $(document).hammer().on('touch transform transformend', '#main', function() {...}); 
0
source share

All Articles