I have a problem with Jquery hover and click on mobile.. Let me explain!
I have square div and, when the mouse is hover it, a new div appear and follow the mouse. You can even click the square div and if so, a new page is opened. The problem now is that, on mobile, I need two click for the new page to be opened, since the first click is read as "hover".
I tried the
$("#mydiv").on('click touchend', function(e)
Actually it works, but with this, if I want to scroll the page on mobile, and I start the swipe on the square div, the new page is opened, which it shouldn't since I didn't click on the square div, just "passed by".
Try using one of those events
https://github.com/benmajor/jQuery-Touch-Events#4-the-events
$('#mydiv').bind('tap', function(e) {
console.log('User tapped #myDiv');
});
As per documentation:
"The event's target is the same element that received the touchstart event corresponding to the touch point, even if the touch point has moved outside that element."
You can see the documentation of touchend also:
https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
If you start your scroll with the square div then square div touchend event will be fired after the release of that finger even after you move your finger to the other elements.
To solve this problem, you can use these events:
https://github.com/benmajor/jQuery-Touch-Events#4-the-events
If you want to stick with this touchend event then there is a workaround:
Declare a global variable i.e.
var isScroll = false, timer;
Apply touchmove eventhandler on document which will fired for touch devices only, this handler detect whether the document is getting scrolled if yes set the isScroll flag to true that will false after 500ms:
$(document).on("touchmove", function(e) {
isScroll = true;
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
isScroll = false;
}, 800);
})
and insert if condition in your eventHandler:
$("#mydiv").on('click touchend', function(e) {
if(!isScroll) {
//insert your code here;
}
}
Related
In a click event (attached to document) I want to figure out the target when the user started pressing the mousebutton.
Example:
User presses mousebutton on a custom popup
User moves the mouse outside the popup and let go
In that case the code below will return a target outside the popup, but I want to figure out if it started within the popup.
$(document).click(function(e)
{
// will return the target during *releasing the mouse button*
// but how to get the target where the *mouse press started*
console.log(e.target);
}
Of course I could track this manually by listening to mousedown and saving this within a variable - but I rather have something native, because:
less code
I might be missing edge cases
Both Jquery or vanilla JavaScript answers are good to me (but preference vanilla)
You could use mousedown together with a mouseup function, and have them both saving their targets to a global variable, then compare them in an if statement.
let downTarget, upTarget;
$(document).mousedown(function(e) {
downTarget = e.target;
});
$(document).mouseup(function(e) {
upTarget = e.target;
});
if(upTarget === downTarget){
*do stuff*
};
just use the event mousedown instead click like
$(document).mousedown(function(e)
{
console.log(e.target);
}
also has another event that verifies if the mouse is over that is the mouseover
In my simple application canvas wrapped by hyperlink. Some objects, which are placed on canvas stage have special mouse interaction on click event. Is there any possible solutions to prevent hyperlink jumping by clicking on objects with my mouse click event listeners?
Normally you can just call preventDefault on the generated mouse event, and it will stop the link event from firing.
element.addEventListener("click", function(e) {
e.preventDefault();
}, false);
This is not possible using EaselJS because although you can access the nativeEvent on any EaselJS mouse event, EaselJS doesn't use the "click" event at all (and instead uses a combination of "mousedown" and "mouseup"). So preventing default on a click event will do nothing.
Doesn't work
// You would expect this to work.
myShape.on("click", function(e) {
e.nativeEvent.preventDefault(); // Nothing. This cancels a "mouseup" instead.
});
Workaround
However, you can work around this pretty easily. Set a flag on the clicked item (or wherever you would set it in your application) any time it is clicked.
myShape.addEventListener("click", function(event) {
myShape.clicked = true;
}, false);
Then, listen for the canvas click event yourself, check and check the flag. Make sure to reset it after. This is possible because "click" is always fired after "mouseup"
stage.canvas.addEventListener("click", function(event) {
if (myShape.clicked) { event.preventDefault(); }
myShape.clicked = false;
}, false);
Here is a quick fiddle showing it working. http://jsfiddle.net/buqkvb1u/
We are looking to see if this makes sense to handle in EaselJS. Thanks for your report!
I'm trying to create a file drag/drop handler (drag a file into the browser window, to be used for upload).
For some reason when I bind the drag/drop listener to $("body") instead of to a $("div") in the body the events fire several times in a row, sometimes even non-stop (seemingly looping). What could be causing this?
Here's a trimmed down version of the code: http://jsfiddle.net/WxMwK/9/
var over = false;
$("body")
.on("dragover", function(e){
e.preventDefault();
if (! over) {
over = true;
$("ul").append($("<li/>").text("dragover"));
}
})
.on("dragleave", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("dragleave"));
}
})
.on("drop", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("drop"));
}
});
To test: drag a file into the orange area, you'll see the event firing multiple times in a row.
The anon is (mostly) correct. To put it simply: when the mouse moves over the edge of an element inside your drop target, you get a dropenter for the element under the cursor and a dropleave for the element that was under the cursor previously. This happens for absolutely any descendant.
You can't check the element associated with dragleave, because if you move the mouse from your drop target onto a child element, you'll get a dropenter for the child and then a dropleave for the target! It's kind of ridiculous and I don't see how this is a useful design at all.
Here's a crappy jQuery-based solution I came up with some time ago.
var $drop_target = $(document.body);
var within_enter = false;
$drop_target.bind('dragenter', function(evt) {
// Default behavior is to deny a drop, so this will allow it
evt.preventDefault();
within_enter = true;
setTimeout(function() { within_enter = false; }, 0);
// This is the part that makes the drop area light up
$(this).addClass('js-dropzone');
});
$drop_target.bind('dragover', function(evt) {
// Same as above
evt.preventDefault();
});
$drop_target.bind('dragleave', function(evt) {
if (! within_enter) {
// And this makes it un-light-up :)
$(this).removeClass('js-dropzone');
}
within_enter = false;
});
// Handle the actual drop effect
$drop_target.bind('drop', function(evt) {
// Be sure to reset your state down here
$(this).removeClass('js-dropzone');
within_enter = false;
evt.preventDefault();
do_whatever(evt.originalEvent.dataTransfer.files);
});
The trick relies on two facts:
When you move the mouse from a grandchild into a child, both dragenter and dragleave will be queued up for the target element—in that order.
The dragenter and dragleave are queued together.
So here's what happens.
In the dragenter event, I set some shared variable to indicate that the drag movement hasn't finished resolving yet.
I use setTimeout with a delay of zero to immediately change that variable back.
But! Because the two events are queued at the exact same time, the browser won't run any scheduled functions until both events have finished resolving. So the next thing that happens is dragleave's event handler.
If dragleave sees that it was paired with a dragenter on the same target element, that means the mouse must have moved from some descendant to some other descendant. Otherwise, the mouse is actually leaving the target element.
Then the setTimeout finally resolves zero seconds later, setting back the variable before another event can come along.
I can't think of a simpler approach.
You are adding a listener on the BODY HTMLElement for the dragover, dragleave and drop.
When you continue to drag over the DIV, there is a dragleave that is fired because the mouse is no more dragging over the BODY, but over the DIV.
Secondly, as you are not stopping the bubble event on the DIV (no listener is set), the dragover fired on the DIV is bubling to the BODY.
If I resume:
The mouse enter the body (in dragover)
--> fire drag over (body)
The mouse enter the DIV in the body
--> fire drag leave (of BODY)
--> fire drag over (of DIV) --> event bubling --> fire drag over (of BODY)
There is a similar problem with mouseover and mouseout, which is fixed by using mouseenter and mouseleave.
May be you can try the same code using dragenter event type. If its not working, you can check if the event.target is the BODY. This test could help to skip undesired drag event.
Good luck
var over = false;
$("body")
.on("dragover", function(e){
e.preventDefault();
if (! over) {
over = true;
$("ul").append($("<li/>").text("dragover"));
}
})
.on("dragleave", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("dragleave"));
}
})
.on("drop", function(e){
e.preventDefault();
if (over) {
over = false;
}
});
Or you could just use stop(); to stop animation buildup
I have a <div> element that is created in my script and appended to another <div>. I have:
coverElm.onmousedown = mouseDownEventHandeler;
document.onmouseup = mouseUpEventHandeler;
document.onmousemove = mouseMoveEventHandeler;
I have the functions defined and work great and keep track of if the mouse is down with a boolean mouseDown.
The Problem - When the mouse is pressed down and is released the document.onmouseup is never handled. I think its because its doing a drag of whatever is in the <div> witch is just a few words of text. I have this issue without text too.
So what I'm looking for is a way to prevent this odd dragging behavior, or way for onmousedrag to see if the mouse is pressed down of not - NOT USING THE MOUSE UP AND MOUSE DOWN METHODS
Here are my functions:
function mouseUpEventHandeler(e) {
mouseDown = false;
}
function mouseDownEventHandeler(e) {
mouseDown = true;
}
function mouseMoveEventHandeler(e) {
if (mouseDown) {
coverElm.innerHTML ="<p>Mouse down and dragging</p>";
}
}
90% of the time, this is because the dragged element is in front of the element with the mouseup event listener, so the parent element underneath never gets the event.
Usually, this can be fixed by using addEventListener as opposed to the inline form of the event. Another way to fix this is to give the dragged element an eventListener for when the mouse is released. Also, you can have a div that is put in front of all other elements whenever an element starts to drag (via the zIndex property).
Edit: I whipped up some proof-of-concept code:
http://jsfiddle.net/2BkEM/5/
$j(divID).bind('dragstart', function (event) { event.preventDefault() });
Thanks all
I am scrolling an overflowing DIV's content by changing the scrollLeft property in Javascript:
setInterval(function(){
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+1);
}, 50);
However, I want to stop this as soon as the user scrolls the content themselves, using the mouse. I tried to detect this using the scroll event
$('#scrollbox').scroll(function(){...});
however, my automatic scrolling above also triggers that event. How can I distinguish this and only react to user-initiated scrolling? (or: how can I stop the above code from firing a scroll event? That would also do the trick)
You could use the .hover(): function to stop the scrolling when the mouse is over the scrollbox element:
http://jsfiddle.net/bGHAH/1/
setInterval(function(){
if(!mouseover)
{
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+1);
}
}, 50);
var mouseover = false;
$('#scrollbox').hover(function(){
mouseover = true;
},function(){
mouseover = false;
});
Edit
Based on your comments I managed to find a jquery plugin from the following site: special scroll events for jquery.
This plugin contains an event which attempts to determine whether scrolling has stopped based on the period of time that has elapsed between the last scroll step and the time the check was made.
To get this to work I needed to slow your interval to just over the latency used by the plugin which worked out to be 310 milliseconds. Doing this meant I had to increase the scroll step to keep it visibly moving.
Here is the link:
http://jsfiddle.net/EWACn/1/
and here is the code:
var stopAutoScroll = false;
$(document).ready(function(){
setInterval(function(){
if(!stopAutoScroll)
{
$('#status').html('scrolling');
$('#scrollbox').scrollLeft($('#scrollbox').scrollLeft()+10);
}else{
$('#status').html('not scrolling');
}
}, 310);
$('#scrollbox').bind('scrollstart', function(e){
stopAutoScroll = true;
});
$('#scrollbox').bind('scrollstop', function(e){
stopAutoScroll = false;
});
});
Hope this helps.
For FF (Mozilla):
document.addEventListener('DOMMouseScroll', handler, false);
For IE, Opera and Chrome:
document.onmousewheel = handler;
Another option is to have an external flag that you can set prior to the programmatic scrolling, and then reset afterwords. If the scroll event is fired and this flag isn't set you know that the user is responsible and can act accordingly.
Unfortunately while this is browser independent and easy to read it could lead you to believe that some user scrolls are programmatic ones. However I would think the occurrences of this is small and may be worth it depending on the app you are writing.
Try wheel event, for most modern browsers
The wheel event is fired when a wheel button of a pointing device (usually a mouse) is rotated.