Disable swiping after first swipe, then reset once done? - javascript

I have the following code which allows me to swipe an element, and the element will move, revealing the element underneath. I'd like to be able to swipe once, have the function run, have the div reset it's position, and allow me to swipe once again. Basically, disable the swiping while the function is running, then enable it once the function is over.
Here's my code:
var threshold = {
x: 30,
y: 10
}
var originalCoord = {
x: 0,
y: 0
}
var finalCoord = {
x: 0,
y: 0
}
function touchMove(event) {
finalCoord.x = event.targetTouches[0].pageX
changeX = originalCoord.x - finalCoord.x
var changeY = originalCoord.y - finalCoord.y
if (changeY < threshold.y && changeY > (threshold.y * -1)) {
changeX = originalCoord.x - finalCoord.x
if (changeX > threshold.x) {
// My function which runs when you swipe left
}
}
}
function touchEnd(event) {
}
function touchStart(event) {
originalCoord.x = event.targetTouches[0].pageX
finalCoord.x = originalCoord.x
}
window.addEventListener("touchstart", touchStart, false);
window.addEventListener("touchmove", touchMove, false);
window.addEventListener("touchend", touchEnd, false);
I figured I could use event.preventDefault() or return false to disable dragging once the function runs, but it still ends up allowing me to drag during it.

Pretty hard to figure out what do you want, but to disable the swiping just add helper variable:
var _swipeDisabled = false;
then in touchmove check if swiping is disabled, and if so just return false:
function touchMove(event) {
if (_swipeDisabled) return false; // this line is crucial
finalCoord.x = event.targetTouches[0].pageX
changeX = originalCoord.x - finalCoord.x
var changeY = originalCoord.y - finalCoord.y
if (changeY < threshold.y && changeY > (threshold.y * -1)) {
changeX = originalCoord.x - finalCoord.x
if (changeX > threshold.x) {
_swipeDisabled = true; // add this before calling your function
// My function which runs when you swipe left
}
}
}
And in your function you'll have to enable the swiping again, so just do:
_swipeDisabled = false;
in the function you call there. Simpliest solutions are usually the best, remember!

I was able to solve this by removing then adding back in the EventListener:
if (changeX > threshold.x) {
window.removeEventListener('touchmove', touchMove, false);
// Function
setTimeout(function () {
window.addEventListener('touchmove', touchMove, false);
}, 800)
}

Related

How to prevent click while scrolling horizontally

I am using cards list with links and it is scrollable horizontally using mouse as well as arrows.
I Want to prevent clicking ( tags) while scrolling/dragging items left or right.
But clicking should work if i am not dragging items.
Here is what I am using in Javascript.
Code
var instance = $(".hs__wrapper");
$.each( instance, function(key, value)
{
var arrows = $(instance[key]).find(".arrow"),
prevArrow = arrows.filter('.arrow-prev'),
nextArrow = arrows.filter('.arrow-next'),
box = $(instance[key]).find(".hs"),
x = 0,
mx = 0,
maxScrollWidth = box[0].scrollWidth - (box[0].clientWidth / 2) - (box.width() / 2);
$(arrows).on('click', function() {
if ($(this).hasClass("arrow-next")) {
x = ((box.width() / 2)) + box.scrollLeft() - 10;
box.animate({
scrollLeft: x,
})
} else {
x = ((box.width() / 2)) - box.scrollLeft() -10;
box.animate({
scrollLeft: -x,
})
}
});
$(box).on({
mousemove: function(e) {
var mx2 = e.pageX - this.offsetLeft;
if(mx) this.scrollLeft = this.sx + mx - mx2;
},
mousedown: function(e) {
this.sx = this.scrollLeft;
mx = e.pageX - this.offsetLeft;
},
scroll: function() {
toggleArrows();
}
});
$(document).on("mouseup", function(){
mx = 0;
});
function toggleArrows() {
if(box.scrollLeft() > maxScrollWidth - 10) {
// disable next button when right end has reached
nextArrow.addClass('disabled');
} else if(box.scrollLeft() < 10) {
// disable prev button when left end has reached
prevArrow.addClass('disabled')
} else{
// both are enabled
nextArrow.removeClass('disabled');
prevArrow.removeClass('disabled');
}
}
});
Try adding a click event handler to the links which prevents default browser behaviour while scrolling. Then, remove the event handler, detecting when scrolling stops using e.g. this method.
var instance = $(".hs__wrapper");
$.each( instance, function(key, value)
{
var arrows = $(instance[key]).find(".arrow"),
prevArrow = arrows.filter('.arrow-prev'),
nextArrow = arrows.filter('.arrow-next'),
box = $(instance[key]).find(".hs"),
x = 0,
mx = 0,
maxScrollWidth = box[0].scrollWidth - (box[0].clientWidth / 2) - (box.width() / 2);
$(arrows).on('click', function() {
if ($(this).hasClass("arrow-next")) {
x = ((box.width() / 2)) + box.scrollLeft() - 10;
box.animate({
scrollLeft: x,
})
} else {
x = ((box.width() / 2)) - box.scrollLeft() -10;
box.animate({
scrollLeft: -x,
})
}
});
$(box).on({
mousemove: function(e) {
var mx2 = e.pageX - this.offsetLeft;
if(mx) this.scrollLeft = this.sx + mx - mx2;
},
mousedown: function(e) {
this.sx = this.scrollLeft;
mx = e.pageX - this.offsetLeft;
},
scroll: function() {
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
$(box).find('a').off('click');
}, 250));
toggleArrows();
$(box).find('a').on('click', function(e) {
e.preventDefault();
});
}
});
$(document).on("mouseup", function(){
mx = 0;
});
function toggleArrows() {
if(box.scrollLeft() > maxScrollWidth - 10) {
// disable next button when right end has reached
nextArrow.addClass('disabled');
} else if(box.scrollLeft() < 10) {
// disable prev button when left end has reached
prevArrow.addClass('disabled')
} else{
// both are enabled
nextArrow.removeClass('disabled');
prevArrow.removeClass('disabled');
}
}
});

How to implement touch controls on my code?

How I put in my funtion moveBloco() to control the white bars through the touch.
I want to make the white bars touchable for a smarthphone user. To move the bars up and down through the touch.
function moveBloco(){
if(87 in keyBoard && left.y > 0)
left.y -= left.speed;
if(83 in keyBoard && left.y + left.altura < canvas.height)
left.y += left.speed;
if(38 in keyBoard && right.y >0)
right.y -= right.speed;
if(40 in keyBoard && right.y + right.altura < canvas.height)
right.y += right.speed;
};
https://jsfiddle.net/bd7v016e/1/
You need to handle touch using TouchEvents. You'll have to add 3 more event listeners corresponding to touchstart, touchmove, and touchend. For a touch you can get the pageX and pageY. You'll have to convert these to position relative to the canvas and apply your logic for moving the bars up or down.
document.addEventListener("touchstart", handleTouchStart, false);
document.addEventListener("touchend", handleTouchMove, false);
document.addEventListener("touchend", handleTouchEnd, false);
var touchPosition = {
x: 0,
y: 0
};
function handleTouchStart(e) {
e.preventDefault();
touchPosition.x = e.changedTouches[0].pageX;
touchPosition.y = e.changedTouches[0].pageY;
var canvasPosition = canvas.getBoundingClientRect();
if (touchPosition.x - canvasPosition.left > canvas.width/2) {
// Trigger Right Bar
if (touchPosition.y - canvasPosition.top > right.y) {
// Move Down the Right Bar
}
else {
// Move Up the Right Bar
}
}
else {
// Trigger Left Bar and apply same logic as above
if (touchPosition.y - canvasPosition.top > right.y) {
// Move Down the left bar
}
else {
// Move Up the left bar
}
}
}
function handleTouchMove(e) {
// Handle When User drags along the touch point
}
function handleTouchEnd(e) {
// Handle Touch End
}

Handling "mousedown" event on different object

I am trying to change the length of two bars (div) by mouse dragging (extending one example in eloquetjavascript book chapter 14, which involves changing the length of one bar by dragging the mouse.) The intended behavior is clicking on any bar, moving the mouse when holding the left mouse key would change the length of that bar.
Here is my implementation (also available on JSfiddle)
<script>
var lastX; // Tracks the last observed mouse X position
var rect1 = document.getElementById("bar1");
var rect2 = document.getElementById("bar2");
rect1.addEventListener("mousedown", function(){watchmousedown(rect1)});
rect2.addEventListener("mousedown", function(){watchmousedown(rect2)});
function watchmousedown(rec) {
if (event.which == 1) {
lastX = event.pageX;
addEventListener("mousemove",function(){moved(rec)});
event.preventDefault(); // Prevent selection
} else {
removeEventListener("mousedown", watchmousedown)}
}
function moved(rec) {
if (event.which != 1) {
removeEventListener("mousemove", moved);
} else {
var dist = event.pageX - lastX;
var newWidth = Math.max(10, rec.offsetWidth + dist);
rec.style.width = newWidth + "px";
lastX = event.pageX;
}
}
</script>
The problem is I can only change the length of the bar where the first mouse click event happened. I assume I didn't handle the mousedown event correctly (probably need a reset some how).
I am new to javascript, help on programming style is also appreciated.
Thanks!
Add rec. to addEventListener("mousemove", function () { so that the event listener is bound to the rec you clicked on instead of to the window.
function watchmousedown(rec) {
if (event.which == 1) {
lastX = event.pageX;
rec.addEventListener("mousemove", function () {
moved(rec)
});
event.preventDefault(); // Prevent selection
} else {
rec.removeEventListener("mousedown", watchmousedown)
}
}
Edit: I there are some event handlers not being cleaned up properly. I don't know if this would be my final code, but this is closer to how I would do it:
var lastX; // Tracks the last observed mouse X position
var rect1 = document.getElementById("bar1");
var rect2 = document.getElementById("bar2");
var moveRect1 = function () {
console.log(arguments);
moved(rect1)
};
var moveRect2 = function() {
console.log(arguments);
moved(rect2);
}
var watchRect1 = function () {
console.log(arguments);
watchmousedown(moveRect1)
};
var watchRect2 = function () {
console.log(arguments);
watchmousedown(moveRect2)
};
rect1.addEventListener("mousedown", watchRect1);
rect2.addEventListener("mousedown", watchRect2);
window.addEventListener("mouseup", function() {
removeEventListener("mousemove", moveRect1);
removeEventListener("mousemove", moveRect2);
});
function watchmousedown(moverec) {
if (event.which == 1) {
lastX = event.pageX;
addEventListener("mousemove", moverec);
event.preventDefault(); // Prevent selection
}
}
function moved(rec) {
if (event.which == 1) {
var dist = event.pageX - lastX;
var newWidth = Math.max(10, rec.offsetWidth + dist);
rec.style.width = newWidth + "px";
lastX = event.pageX;
}
}
Edit: removed a line that didn't do anything

Event .on and .off

I am having a few issues with some events I am making.
On my document.ready I have:
jQuery(document).ready(function () {
//deal with clicks
jQuery(".touchslider-prev").click( function() {
jQuery(window).trigger('swipeForward');
});
jQuery(".touchslider-next").click( function() {
jQuery(window).trigger('swipeBackward');
});
//deal with swipe
var maxTime = 1000,
// allow movement if < 1000 ms (1 sec)
maxDistance = 50,
// swipe movement of 50 pixels triggers the swipe
target = jQuery('.pageSize'),
startX = 0,
startTime = 0,
touch = "ontouchend" in document,
startEvent = (touch) ? 'touchstart' : 'mousedown',
moveEvent = (touch) ? 'touchmove' : 'mousemove',
endEvent = (touch) ? 'touchend' : 'mouseup';
target.bind(startEvent, function(e) {
// prevent image drag (Firefox)
// e.preventDefault();
startTime = e.timeStamp;
startX = e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX;
}).bind(endEvent, function(e) {
startTime = 0;
startX = 0;
}).bind(moveEvent, function(e) {
// e.preventDefault();
var currentX = e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX,
currentDistance = (startX === 0) ? 0 : Math.abs(currentX - startX),
// allow if movement < 1 sec
currentTime = e.timeStamp;
if (startTime !== 0 && currentTime - startTime < maxTime && currentDistance > maxDistance) {
if (currentX < startX) {
// swipe left code here
console.log("page forward trigger");
jQuery(window).trigger('swipeForward');
}
if (currentX > startX) {
// swipe right code here
console.log("page back trigger");
//slide("back", pageSize);
jQuery(window).trigger('swipeBackward');
}
startTime = 0;
startX = 0;
}
});
//handle triggers from click and slide
jQuery(window).on('swipeForward', clickHandlerNext );
jQuery(window).on('swipeBackward', clickHandlerPrev );
});
If I then click forward or swipe forward this should trigger swipeForward which brings this bit of code into play jQuery(window).on('swipeForward', clickHandlerNext );
so the function clickHandlerNext should be run
function clickHandlerPrev(event) {
if(event.handled !== true) {
// Kill event handler, preventing any more clicks
jQuery(window).off("click", clickHandlerPrev);
jQuery(window).off("click", clickHandlerNext);
console.log("switch off handlers");
// Do your stuff here
slide("back");
// Mark event as handled
event.handled = true;
}
return false;
}
function clickHandlerNext(event) {
// If event isn't already marked as handled, handle it
if(event.handled !== true) {
// Kill event handler, preventing any more clicks
jQuery(window).off("click", clickHandlerPrev);
jQuery(window).off("click", clickHandlerNext);
console.log("switch off handlers");
// Do your stuff here
slide("forward");
// Mark event as handled
event.handled = true;
}
return false;
}
this should switch off the handler and then run the slide function.
function slide(data) {
jQuery('#pageHolder').animate({
left: 950
}, 400, function() {
console.log("animation started");
console.log("switch on handles");
jQuery(window).on("click", clickHandlerPrev);
jQuery(window).on("click", clickHandlerNext);
console.log("animation complete");
});
}
This then turns back on the handler. If I however remove the line jQuery(window).on("click", clickHandlerPrev); the next time I press the button it still runs the handler - but it shouldn't as it should be set .off.
Can anyone help?
Is jQuery.one an option? It applies the handler just once.

Get element on touchstart?

I have a series of divs on a page which you can swipe left on, which will reveal a div underneath. This works fine when there is only one element, but when there are multiple, they all swipe in unison, instead of the one getting swiped alone.
To remedy this, I tried the ideas here: Find element finger is on during a touchend event
Problem is, now only the first element gets swiped, while the rest of them stay stationary. Any ideas on how I could fix this? I thought I could use this, but it would always return the window object.
Code:
var originalCoord = {
x: 100,
y: 100
}
var finalCoord = {
x: 100,
y: 100
}
function touchMove(event) {
event.preventDefault();
finalCoord.x = event.targetTouches[0].pageX
finalCoord.y = event.targetTouches[0].pageY
}
function touchEnd(event) {
var changeY = originalCoord.y - finalCoord.y
if (changeY < 30 && changeY > (30 * -1)) {
changeX = originalCoord.x - finalCoord.x
if (changeX > 10) {
var elem = document.elementFromPoint(event.pageX, event.pageY);
console.log(elem);
$(elem).css("margin-left", "-54px");
setTimeout(function () {
$(elem).css("margin-left", "0px");}
, 500);
}
}
}
function touchStart(event) {
originalCoord.x = event.targetTouches[0].pageX
originalCoord.y = event.targetTouches[0].pageY
finalCoord.x = originalCoord.x
finalCoord.y = originalCoord.y
}
this.addEventListener("touchstart", touchStart, false);
this.addEventListener("touchmove", touchMove, false);
this.addEventListener("touchend", touchEnd, false);
Demo (only works on iOS): http://www.codekraken.com/testing/snowday/swipe.html
You can get the element which the event originated in by using event.target.
function touchStart(event){
var currentElement = event.target;
}
$('#id').on('touchstart',function(e,data) {
var obj = e.target;
obj = $(this);
var id = obj.find....
});
with obj = $(this) you can transform event.target into a jquery-object using jquery functions...
best
M

Categories