jquery draggable x axis disable page scroll on mobile - javascript

I am making a slider that have 3 images and they are draggable with limits , I am using UI touch punch to make the mobile drag work.
This is my js code so far :
$(".draggable").draggable({
axis: "x",
drag: function(event, ui) {
//$(window).scrollTo(0, scrollPage);
//window.scrollBy(0,scrollPage);
if (ui.position.left > 0) {
newLeft = 0;
} else if (ui.position.left < max_drag) {
newLeft = max_drag;
} else {
newLeft = ui.position.left;
}
ui.position.left = newLeft;
}
});
and this is what i want to achieve :
now everything works except on mobile when i scroll vertically over the draggable element it doesn't scroll even tho the draggable is only on x axis.
I have searched and fuond this :
jQuery UI draggable prevents scrolling on mobile
And
jQuery UI Draggable and Page Scrolling (on mobile)
but I couldnt get a clear solution or answer.

Related

How to use window.scroll with horizontal scroll to get element position

I'm trying to get element position while scrolling in a horizontal web page. I tried to use
main scrolling:
$('html, body, *').mousewheel(function(e, delta) {
this.scrollLeft -= (delta*60);
});
then:
$(window).scroll(function() {
alert('Anything');
});
But that doesn't work at all. I tried using mousewheel plugin
$('.internal.th').on('mousewheel',function(event) {
console.log(event.deltaX, event.deltaY, event.deltaFactor);
});
But it keeps displaying the same position -0 -1 100 no matter how much i scroll
I tried
$('.internal.th').on('scroll', function() {
var val = $(this).scrollLeft()
if (val >= 100) alert('Hello')
})
but it doesn't do anything at all
The idea is getting some item position from the left related to the window to manage another element rotation so I want to keep tracking the main item positing while scrolling horizontally not vertically
jQuery provides APIs
offset
position
you can use those
Below is a sample with both vertical and horizontal scrollbars
$(document).ready(function(){
document.addEventListener('scroll', function (event) {
console.log(event.target);
console.log($("#p3").position());
console.log($("#p3").offset());
console.log($("#p3").position().top - $("body").scrollTop());
console.log($("#p3").position().left - $("body").scrollLeft());
}, true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>dasdasd</p>
<p>dasdasd</p>
<p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p>
<p style="width: 2500px;display:inline-block">dasdasd<div ></div></p>
<p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p id="p3">dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p><p>dasdasd</p>
Important: position and offset is relative to parent tag's position and offset

How can I use jQuery Slider Ui and Draggable together?

Let's say I have created something similar to this: Link
Now I want to move content with drag.
So far so good and I was able to move them using jQuery UI Draggable.
I change the slider position when the content being dragged.
But when I move the content with drag and after that when I want to use slider button to move content, the position of content is wrong and not working.
Here is my code so far :
slider.slider({
orientation : 'horizontal',
max : w_width -(one_divs_w*numberOfItemVisibleInScreen),//total width minus one content div width
min : 0,
value : 0,
slide : function(event, ui) {
fp_thumbScroller.scrollLeft(ui.value);
},
});
//initialize the draggable
fp_content_wrapper.draggable({
axis: 'x',
cursor: "move",
drag: function (event, ui) {
maxDrggable = - (w_width -(one_divs_w*numberOfItemVisibleInScreen));
if (ui.position.left < maxDrggable) {
ui.position.left = maxDrggable;
}
if (ui.position.left > 0) ui.position.left = 0;
// ****
// set position for slider
// *****
slider.slider('value', -(ui.position.left));
},
});
should I change the position of draggable when moving content with slider ?

Draggable containment buggs when the draggable element is rotated

I have a draggable element, which is also resizable and rotatable. These rotations are handled by CSS transformations, however, when an element is rotated, it makes the draggable feature spin out of control.
Heres a (updated) fiddle: Click me
What I think happens is that when an element is rotated, it's height and width obviously stay the same, just at an angle, however, jQuery doesn't account for the rotation, making it think that the element is in it's normal horizontal way, which results in the "bugg" shown in the fiddle above.
In a wild goose chase for the answer, I read somewhere that this would do the trick:
refreshPositions: true,
But it didn't work. Neither did destroying the draggable function on the element and then reinitiating it. Is there a way to fix this, so the containment will function normally, thus making jQuery recognise the rotation?
Thanks.
One option is to handle the containment yourself. Here is one possible way to do that.
I am using getBoundingClientRect to get the height and width of the rotated element. Using these values I can get an idea of where the dragged element resides in relation to it's parent container and force it to stay within those bounds.
var boundingContainer, boundingDraggable, prevLeft, prevTop;
$(".draggable").draggable({
classes: {
"ui-draggable-dragging": "highlight-draggable"
},
start: function(event, ui) {
boundingDraggable = ui.helper[0].getBoundingClientRect();
boundingContainer = ui.helper.closest('#draggableContainer')[0].getBoundingClientRect();
},
drag: function(event, ui) {
if(ui.offset.left <= boundingContainer.left){
if(ui.position.left < prevLeft){
ui.position.left = prevLeft;
}
}
if(ui.offset.top <= boundingContainer.top){
if(ui.position.top < prevTop){
ui.position.top = prevTop;
}
}
if(ui.offset.left+boundingDraggable.width >= boundingContainer.right){
if(ui.position.left > prevLeft){
ui.position.left = prevLeft;
}
}
if(ui.offset.top+boundingDraggable.height >= boundingContainer.bottom){
if(ui.position.top > prevTop){
ui.position.top = prevTop;
}
}
prevLeft = ui.position.left;
prevTop = ui.position.top;
}
});
Fiddle

jQuery UI draggable prevents scrolling on mobile

I have draggable elements with full screen width listed vertically.
I am using a plugin called (jquery.ui.touch-punch) to enable jQuery draggable on mobile. But the problem is that the draggable elements prevent the user from scrolling the page.
$('#novieList .element .content').draggable({
axis: 'x',
revert: function() {
return $(this).position().left < 30;
},
containment: [ 0, 0, 75, 0 ],
scope: 'element',
scroll: false,
delay: 300,
drag: function(event, ui) {
return true;
},
start: function(event, ui) {
// Prevent to drag the element after open it
var left = $(this).position().left;
return left == 0;
},
stop: function(event, ui) {
var left = $(this).position().left;
if (left != 0) {
$(this).offset({left: 75});
}
return true;
}
});
I don't believe commenting out event.preventDefault() in jquery.ui.touch-punch.js works any longer. I tried the same solution and found that jQuery UI draggable itself was blocking the default behavior of a vertical scroll -- even when the element is set to drag only along the x-axis.
The solution that worked for me was to measure any change in the cursor's vertical position and use window.scrollBy to manually scroll the window by the same amount:
var firstY = null;
var lastY = null;
var currentY = null;
var vertScroll = false;
var initAdjustment = 0;
// record the initial position of the cursor on start of the touch
jqDraggableItem.on("touchstart", function(event) {
lastY = currentY = firstY = event.originalEvent.touches[0].pageY;
});
// fires whenever the cursor moves
jqDraggableItem.on("touchmove", function(event) {
currentY = event.originalEvent.touches[0].pageY;
var adjustment = lastY-currentY;
// Mimic native vertical scrolling where scrolling only starts after the
// cursor has moved up or down from its original position by ~30 pixels.
if (vertScroll == false && Math.abs(currentY-firstY) > 30) {
vertScroll = true;
initAdjustment = currentY-firstY;
}
// only apply the adjustment if the user has met the threshold for vertical scrolling
if (vertScroll == true) {
window.scrollBy(0,adjustment + initAdjustment);
lastY = currentY + adjustment;
}
});
// when the user lifts their finger, they will again need to meet the
// threshold before vertical scrolling starts.
jqDraggableItem.on("touchend", function(event) {
vertScroll = false;
});
This will closely mimic native scrolling on a touch device.
I found a solution to that problem at Scrolling jQuery UI touch punch. You have to remove a event.preventDefault() in jquery.ui.touch-punch.js on line 38. So far I have only tested on Sony Xperia Z1 Compact, Android 5, Chrome, but it works very well in a project very similar to one named here.
I had the problem regarding that I could scroll on mobile when my div was dragable, as the CSS of the Jquery UI had the following code set to none, so by reverting the changes by putting them on initial everything worked again!
.ui-draggable-handle {-ms-touch-action:initial!important;touch-action:initial!important}

Best way of making draggable element jump to cursor (and start drag) when mousedown on parent

I've got a home-made slider made from jQuery UI's draggable() function:
$("#petrolGauge .fuelBar .slider").draggable({
containment: "parent",
axis: "x",
drag:function(){
updValues();
},
start:function(){
$(this).css("background-color","#666");
},
stop:function(){
//checkForm();
$(this).css("background-color","#AAA");
}
});
This is for the following markup:
<div id="petrolGauge">
<input id="endPet" name="endPet" type="hidden" value="0">
How much fuel was left in the tank when you were finished? (Use the slider) <b>(~<span class="petLeft">0</span>%)</b>
<span class="mandatory">*</span><br />
<div class="fuelBar">
<div title="Drag" class="slider"></div>
</div>
This works a treat, when I click on the slider. But I'd like it so that when I click the fuel bar (the slider's parent) the slider not only starts dragging but also jumps to the cursor. I've achieved it by doing this:
$("#petrolGauge .fuelBar").on("mousedown",function(e){
slider = $("#petrolGauge .fuelBar .slider");
left = e.pageX-($(this).offset().left)-(slider.width()/2);
updValues();
slider.css("left",left).trigger(e);
});
Two problems with this:
Firstly, when clicking on the parent I get a couple of second's delay before the slider starts to drag? I've tried and tested this in Chrome and IE and both do it. Secondly if the cursor is less than half of the slider's width away from the edge of the parent, the slider will move to the outside of the parent. Wouldn't be hard to fix this with a couple of checking, but was wondering if there was another way? I'm suprised that draggable() doesn't have any parameters for this to be honest. I didn't want to use slider() if I could help it but if it's the only way, then it's the only way.
Here's a fiddle to work with.
The reason you get the delay is because you use .trigger() inside the .on() event which creates a big loop. As a result the loop slows down the moving process.
$("#petrolGauge .fuelBar").click(function (e) { // use click instead of mousedown
slider = $("#petrolGauge .fuelBar .slider");
left = e.pageX - ($(this).offset().left) - (slider.width() / 2);
if(left > 570) { left = 570; } else if(left < 0) { left = 0; }
// it looks like a draggable bug due to the manual position change, so use a small check
slider.css("left", left); // change the position first
updValues(); // then calculate and update the div
// no need to trigger the event a second time because it will loop until jQuery exceeds it's trigger limit.
});
Here's an updated FIDDLE
Updated answer
To make .slider move accordingly to the mouse movement when not directly dragged, bind a mousemove event to the mousedown and unbind it when mouseup. Then in .mousemove() you change the position of .slider.
var move = function (e) {
left = e.pageX - ($('#petrolGauge .fuelBar').offset().left) - (slider.width() / 2);
if (left > 570) {
left = 570;
} else if (left < 0) {
left = 0;
}
slider.css("left", left);
updValues();
};
var slider = $("#petrolGauge .fuelBar .slider");
$("#petrolGauge .fuelBar").mousedown(function (e) {
e.preventDefault();
left = e.pageX - ($(this).offset().left) - (slider.width() / 2);
if (left > 570) {
left = 570;
} else if (left < 0) {
left = 0;
}
slider.css("left", left)
$(this).bind('mousemove', move);
updValues();
}).mouseup(function () {
$(this).unbind('mousemove');
});

Categories