is it possible to check the state of the mousebutton (pressed or released). I know that this is the purpose of the eventhandling in jquery, but I wonder if it would be possible to do a function if the button of the mouse isn't pressed without the need of a change in position of the button (pressed to released or vice versa)?
Try below code, DEMO here
$(document).mousedown (function () {
$('#result').text('Pressed');
}).mouseup (function () {
$('#result').text('Released');
});
$(function () {
//setup flag for the state of the mouse button and create an object that converts an event type into a boolean for the flag
var mousePressed = false,
mouseConvert = {
mousedown : true,
mouseup : false
};
//bind to the document's mousedown and mouseup events to change the flag when necessary
$(document).on('mousedown mouseup', function (event) {
//set the flag to the new state of the mouse button
mousePressed = mouseConvert[event.type];
//if you only want to watch one mouse button and not all of them then
//you can create an if/then statement here that checks event.which
//and only updates the flag if it is the button you want, check-out Rob W.'s
//answer to see the different values for event.which with respect to the mouse
});
//now you can check the value of the `mousePressed` variable, if it is equal to `true` then the mouse is currently pressed
});
You can use the mousedown and mouseup event to detect changed mouse events. This event should be bound to window. Demo: http://jsfiddle.net/uwzbn/
var mouseState = (function(){
var mousestatus = 0;
$(window).mousedown(function(e) {
mousestatus = e.which;
}).mouseup(function(e){
mousestatus = 0;
});
return function() {
return mousestatus;
}
})();
This function returns four possible values:
0 Mouse released false
1 Left click true
2 Middle click true
3 Right click true
In a boolean context, the function return's value evaluates to false when the mouse is not down. When the mouse is pressed, you can read which mouse key is pressed (as a bonus).
Related
I am trying to catch when user press left button on mouse while hovering over cells in a html table using vanilla javascript. The purpose is to paint a cell in black when user is clicking with mouse while dragging (drawing like in MsPaint, when you draw a line for example)
I added an "over" event listener on each td of my table and used buttons property to check if left button is pressed or not:
celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("mouseover", function(e){
if(e.buttons == 1 ){
e.target.style.backgroundColor="black";
}
})
This code works but not always and not perfectly. First it starts setting the background color of the next element, not the one on which I pressed the mouse. Moreover, sometimes it doesn't set any color at all (there is a small icon like "accessed denied" in Chrome's window). It appears to work quite randomly and unpredicatably.
I tried also with jQuery, but I found similar problems. Anyone can help me?
Thanks a lot
Split the problem into several parts. I would add a mousedown and mouseup eventlistener to the whole window and set a global state if you're currently drawing:
var drawState=false
window.addEventListener("mousedown",function(e){
if(e.button===1){
drawState = true;
}});
window.addEventListener("mouseup",function(e){
if(e.button===1){
drawState = false;
}});
You can improve the window listeners with some checks, if the mouse is over a cell.
After this you can add a mouseenter listener to all your cells. Mouseenter is only fired once you enter a cell and not on every move inside the element:
celle[i].addEventListener("mouseenter", function(e){
if(drawState){
e.target.style.backgroundColor="black";
}
})
Instead of tracking mouseover, track three events:
mousemove - to constantly get the mouse position
mousedown - to set the mouse state as currently clicked down
mouseup - to set the mouse state as currently released
It works this way:
handleMousemove constantly updates the mouse position and check mouse state
When the mouse is clicked down, handleMousedown is fired
handleMousedown set the state as 'down'
When handleMousemove sees that mouse state is 'down', it fires click event at the current mouse position
When the mouse is released, handleMouseup is fired
handleMouseup set the state as 'released' and everything returns to normal
Repeat
var mouseIsDown = false;
var mousePosition = { x:-1, y:-1 };
let handleMousemove = (event) => {
// get the mouse position
mousePosition.x = event.x;
mousePosition.y = event.y;
if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
{
let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
// you can add some conditions before clicking
if(something)
{
elem.click();
}
}
};
let handleMousedown = (event) => {
mouseIsDown = true;
// set the mouse state as 'down'
};
let handleMouseup = (event) => {
mouseIsDown = false;
// set the mouse state as 'release'
};
document.addEventListener('mousemove', handleMousemove);
document.addEventListener('mousedown', handleMousedown);
document.addEventListener('mouseup', handleMouseup);
Working fiddle: https://jsfiddle.net/Black3800/9wvh8bzg/5/
Thanks to everybody for your kind answers. Proposed codes work almost ok. The only problem is that sometimes browser shows the NO SYMBOL cursor. Unfortunately I can't post an image but you can find it here:
NO Symbol
and the only way to keep on drawing is clicking outside the table and then clicking again inside.
This is my code:
var mouseIsDown = false;
var mousePosition = { x:-1, y:-1 };
let handleMousemove = (event) => {
// get the mouse position
mousePosition.x = event.x;
mousePosition.y = event.y;
if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
{
let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
// you can add some conditions before clicking
if (event.buttons==1)
{
elem.click();
}
}
};
let handleMousedown = (event) => {
mouseIsDown = true;
// set the mouse state as 'down'
};
let handleMouseup = (event) => {
mouseIsDown = false;
// set the mouse state as 'release'
};
document.addEventListener('mousemove', handleMousemove);
document.addEventListener('mousedown', handleMousedown);
document.addEventListener('mouseup', handleMouseup);
celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("click", function(e){
e.target.style.backgroundColor="black";
}
)
Isn't it easier to just add a listener for "click" ? If the element is clicked it also over the cell.
celle[i].addEventListener("click", function(e){
e.target.style.backgroundColor="black";
}
I want to be able to use a ul list as an select form element, for styling reasons.
I'm able to populate an hidden input with my code (not included in this jsfiddle), and so far so good.But now I'm trying to let my ul behave like the select input when the keyboard is pressed, or the mouse is used.
In my previous question i had some problems with keyboard controls. They are now fixed. See: Autoscroll on keyboard arrow up/down
The problem that remains is that the mouse is not ignored when the keyboard buttons are pressed. This is causing the "hover effect" to listen to the keyboard input first, but than immediately going to the mouse and select this li item as being selected.
This can be seen in my jsfiddle example: http://jsfiddle.net/JVDXT/3/
My javascript code:
// scrollTo plugin
$.fn.scrollTo = function( target, options, callback ){
if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
var settings = $.extend({
scrollTarget : target,
offsetTop : 100,
duration : 0,
easing : 'linear'
}, options);
return this.each(function(){
var scrollPane = $(this);
var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
if (typeof callback == 'function') { callback.call(this); }
});
});
}
//My code
//The function that is listing the the mouse
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
})
//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
if (e.keyCode == 38) { // up
console.log('keyup pressed');
var selected = jQuery('.selected');
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
if (selected.prev().length == 0) {
selected.siblings().last().addClass('selected');
} else {
selected.prev().addClass('selected');
jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
}
}
if (e.keyCode == 40) { // down
console.log('keydown');
var selected = jQuery('.selected');
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
if (selected.next().length == 0) {
selected.siblings().first().addClass('selected');
} else {
selected.next().addClass('selected');
jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
}
}
});
So could anyone teach me how to igonore the mouse when the keyboard buttons are pressed, but listing to the mouse when it's touched again by the user. Like the default select input form field.
Update
Here's a new jsfiddle.
Check this out:
http://jsfiddle.net/coma/9KvhL/25/
(function($, undefined) {
$.fn.dropdown = function() {
var widget = $(this);
var label = widget.find('span.valueOfButton');
var list = widget.children('ul');
var selected;
var highlighted;
var select = function(i) {
selected = $(i);
label.text(selected.text());
};
var highlight = function(i) {
highlighted = $(i);
highlighted
.addClass('selected')
.siblings('.selected')
.removeClass('selected');
};
var scroll = function(event) {
list.scrollTo('.selected');
};
var hover = function(event) {
highlight(this);
};
var rebind = function(event) {
bind();
};
var bind = function() {
list.on('mouseover', 'li', hover);
widget.off('mousemove', rebind);
};
var unbind = function() {
list.off('mouseover', 'li', hover);
widget.on('mousemove', rebind);
};
list.on('click', 'li', function(event) {
select(this);
});
widget.keydown(function(event) {
unbind();
switch(event.keyCode) {
case 38:
highlight((highlighted && highlighted.prev().length > 0) ? highlighted.prev() : list.children().last());
scroll();
break;
case 40:
highlight((highlighted && highlighted.next().length > 0) ? highlighted.next() : list.children().first());
scroll();
break;
case 13:
if(highlighted) {
select(highlighted);
}
break;
}
});
bind();
};
$.fn.scrollTo = function(target, options, callback) {
if(typeof options === 'function' && arguments.length === 2) {
callback = options;
options = target;
}
var settings = $.extend({
scrollTarget : target,
offsetTop : 185,
duration : 0,
easing : 'linear'
}, options);
return this.each(function(i) {
var scrollPane = $(this);
var scrollTarget = (typeof settings.scrollTarget === 'number') ? settings.scrollTarget : $(settings.scrollTarget);
var scrollY = (typeof scrollTarget === 'number') ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop, 10);
scrollPane.animate({scrollTop: scrollY}, parseInt(settings.duration, 10), settings.easing, function() {
if (typeof callback === 'function') {
callback.call(this);
}
});
});
};
})(jQuery);
$('div.btn-group').dropdown();
The key is to unbind the mouseover and rebind when mouse moves.
I refactored it a little by using a closure function, adding the logic to a jQuery method called dropdown so you can reuse it, using switch instead of a bunch of if's and more things.
Well, there are bazillions of plugins to transform a select to a list:
http://ivaynberg.github.io/select2/
http://harvesthq.github.io/chosen/
http://meetselva.github.io/combobox/
and I have mine too! (ready for touch devices using the same trick as http://uniformjs.com)
https://github.com/coma/jquery.select
But this question is about taking that HTML and make it behave like a select avoiding the hover issue right?
Here's a solution, I'm using mousemove as this will ensure that the right list item is selected as soon as the mouse starts moving again, with mouseover it only starts to select a list item upon entering a new list item:
Take the anonymous function and give it a name:
function mousemove() {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
}
Declare a global variable mousemoved indicating if the mouse has moved over the document and set it to false, on mousemove over the document, set it to true and attach the mousemove function to the mousemove event on the list items.
var mousemoved = false;
jQuery(document).mousemove(function() {
if(!mousemoved) {
$('.btn-group .dropdown-menu li').mousemove(mousemove);
mousemoved = true;
}
})
As soon as a key is pressed (at the start of the keydown event), use jQuery's .off() method to remove the mousemove event on the list items if it is present, and set mousemoved to false to ensure the mousemove event doesn't get attached again until the mouse is moved again.
jQuery(".btn-group").keydown(function(e) {
$('.btn-group .dropdown-menu li').off('mousemove');
mousemoved = false;
... // Some more of your code
Here's a jsFiddle.
I tried to solve your issue by prevent autoscroll, adding tabindex on the li, setting the focus on active, and using a flag to suppress mouse.
Fixed fiddle: http://jsfiddle.net/8nKJT/ [fixed an issue in Chrome ]
http://jsfiddle.net/RDSEt/
The issue is because of the automatic scroll which is triggered on keydown that again triggers mouseenter messes the selection of the li.
Note: The differences with the other approaches(answers here) I noticed is it scrolls on every keypress instead of scrolling only after reaching the top or bottom(normal behavior). You will feel the difference when you check the demo side-by-side.
Below is the list of change description and a small demo to explain how it was fixed,
Prevented auto scroll that is triggered on pressing up arrow/down arrow using e.preventDefault() http://jsfiddle.net/TRkAb/ [press up/down on the ul li], Now try the same on http://jsfiddle.net/TRkAb/1/ [No more scroll]
Added a flag on keydown to suppress the mouseevents on keydown, this flag is reset onmousemove
Added tabindex to li which would allow you to set focus using .focus function. [More info: https://stackoverflow.com/a/6809236/297641 ]
Calling .focus would automatically scroll to the desired location. (no need for scrollTo plugin) http://jsfiddle.net/39h3J/ - [Check how it scrolls to li that is on focus]
Check out the demo and code changes too (added few improvements) and let me know.
Also thanks to your question, I noticed this issue and bunch of other issue in one of the plugin I wrote.
I wrote a plugin few months back to filter options and also act exactly like a drop down.
DEMO: http://jsfiddle.net/nxmBQ/ [change filterType to '' to turnoff the filtering ]
The original plugin page is http://meetselva.github.io/combobox/
.. more
You could use a global to ignore the mouseover event if a keydown was pressed recently on the widget. For example:
var last_key_event = 0;
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
if ((new Date).getTime() > last_key_event + 1000) {
console.log('mousie')
jQuery(".btn-group .dropdown-menu li").removeClass('selected');
jQuery(this).addClass('selected');
}
});
Then the keydown handler can set when it was handled to avoid interaction with the mouse:
//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
last_key_event = (new Date).getTime();
...
});
May be it could make sense to have the last_key_event variable separate for each widget instead of being a global.
You could try this solution. It ignores the mousemove event if the coordinates have not changed (since the last mousemove event)
//The function that is listing the the mouse
var lastOffsets = "";
jQuery(".btn-group .dropdown-menu li").mouseover(function(e) {
var curOffsets = e.clientX+":"+e.clientY;
if(curOffsets == lastOffsets) {
// mouse did not really move
return false;
}
lastOffsets = curOffsets;
///// rest of your code
}
Updated fiddle to verify if this is what you were after:
http://jsfiddle.net/pdW75/1/
Approach A reasonable solution should imitate the behavior of other UI elements that serve a similar purpose. On all checked systems (Windows, Linux, major browsers), drop-down boxes behave as follows:
Mousing over an item highlights it. Pressing arrow keys change the selected element, and scroll accoringly. Moving the mouse selects the element underneath. If the selection is empty, pressing down selects the first element. Pressing up selects the last element.
Solution This code illustrates my approach to imitating the described behavior. It's kinda cool, try it...
Additional Considerations There would be a number of other options to suppress unwanted mouse movement to change the selected element. These include:
Keeping a state of last input method. If last selection was using the keyboard, hovering over an element will not select it, only clicking will
ignoring the mouseover event if the coordinates have not changed by a specified distance, e.g. 10 pixels
ignoring mouseover if the user has ever used the keyboard
However, at least for an application accessible to the public, it's always best to stick with established UI patterns.
The problem showing up is that when the mouse is left over a part of the expanded list, then selecting using the keys is nullified because the selection made by the keyboard immediately reverts to the item that happens to be under the mouse.
You can solve this problem and retain all functionality without doing any complicated conditional behavior or any removing of event handlers.
Just change your mouseover event handler to be a mousemove event handler. This way any keyboard navigation and selection is listened to and the mouse position is ignored anytime that the user is using the keyboard to select. And anytime the mouse is being used to select, then the mouse is listened to.
This sounds trivial but it seems to make your JS Fiddle behave perfectly and without any conflicting behavior between mouse and keyboard. Like this:
//The function that is listening to the mouse
jQuery(".btn-group .dropdown-menu li").mousemove...
(your code continues unchanged, only replacing mouseover with mousemove)
Hi I want to have a dblclick() on the right click as the google maps have to zoom in and zoom out. Is there any way to do that. I have written the dblclick but now its working with only left click. Any pointers on how to do this. Here is my code
$("div#demo1").dblclick(function(e) {
//alert(e.getElementById());
if( (!$.browser.msie && e.button == 0) || ($.browser.msie && e.button == 1) ) {
alert("Left Mouse Button was clicked on demo1 div!");
$("div.window").animate({
'height':'+=20', 'width':'+=20'
},0,function(){
jsPlumb.repaintEverything();
jsPlumb.repaintEverything();
});
// Left mouse button was clicked (all browsers)
}
else if( (!$.browser.msie && e.button == 2) || ($.browser.msie && e.button == 3) ) {
alert("right click double");
}
});
There is another way you could detect a double right-click that does not involve fiddling with timers or keeping track of click counts manually. Using the .detail property of the event object in a mouseup or mousedown event. .detail holds the click count which will tell you how many clicks have happened recently. If .detail === 2 it was a double-click.
// suppress the right-click menu
$('#target').on('contextmenu', function (evt) {
evt.preventDefault();
});
$('#target').mouseup(function (evt) {
if (evt.which === 3) { // right-click
/* if you wanted to be less strict about what
counts as a double click you could use
evt.originalEvent.detail > 1 instead */
if (evt.originalEvent.detail === 2) {
$(this).text('Double right-click');
} else if (evt.originalEvent.detail === 1) {
$(this).text('Single right-click');
}
}
});
You might notice that I am using evt.originalEvent.detail to access the property instead of just .detail. This is because jQuery provides it's own version of the event object which does not include .detail, but you can access the original event object that the browser returned via .originalEvent. If you were using pure JavaScript instead of jQuery you would just use evt.detail.
Here's a working example.
There is no real way to do it, you can emulate it by taking the default timer for double clicks which IIRC is 300ms:
function makeDoubleRightClickHandler( handler ) {
var timeout = 0, clicked = false;
return function(e) {
e.preventDefault();
if( clicked ) {
clearTimeout(timeout);
clicked = false;
return handler.apply( this, arguments );
}
else {
clicked = true;
timeout = setTimeout( function() {
clicked = false;
}, 300 );
}
};
}
$(document).contextmenu( makeDoubleRightClickHandler( function(e) {
console.log("double right click" );
}));
http://jsfiddle.net/5kvFG/2/
Because the right-click has meaning to the user agent that is outside the purview of javascript (the context menu), you're going to have to do some dancing around.
First, you should disable the context menu on the target element:
document.getElementById('demo1').oncontextmenu = function() {
return false;
};
Now, when we right click, there won't be the context menu messing up the second click.
Next, understand that "double-click right" does not, generally speaking, exist. Even though you can bind the dblclick event, that isn't a generic event. "Double-click" is, by definition, double-clicking with the left mouse button.
So, we'll have to use the mousedown event, check to see how many times the right has been clicked, and react after two. I created a small helper function that keeps track of the click count and resets the state after a short time-frame.
var RightClick = {
'sensitivity':350,
'count':0,
'timer':false,
'active':function () {
this.count++;
this.timer = setTimeout(
this.endCountdown.bind(this),
this.sensitivity
);
},
'endCountdown': function () {
this.count = 0;
this.timer = false;
}
};
$("div#demo1").mousedown(function(e) {
if(e.which == 3) {
RightClick.active();
if (RightClick.count == 2)
alert("right click double");
}
});
Try it here: http://jsfiddle.net/94L7z/
You can adjust the sensitivity rate, allowing for shorter or longer double-clicks, depending on your preference.
Documentation
element.onContextMenu on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.oncontextmenu
element.onMouseDown on MDN - https://developer.mozilla.org/en-US/docs/DOM/element.onmousedown
window.setTimeout on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout
jQuery event.which - http://api.jquery.com/event.which/
"Javascript Madness: Mouse Events" on UnixPapa.com, an article showing some tests related to mouse events and the left/right buttons - http://unixpapa.com/js/mouse.html
The problem is the concept of double clicking is only relevant to the left mouse button as far as JS is concerned. So no matter how many time, and how fast you click the right mouse button, it just registers as a bunch of single clicks. So what to do?
Create a global variable to track click count
detect a single right-click, you already know how to do this it seems
set the global variable that the right-click was fired once
set a timeout, so if another right click doesn't come through in a
reasonable time to be considered a dblclick the global variable
resets to 0. I recommend 300 ms, it seems to be the most natural
each time a right-click registers check that variable, if it's more
than one, fire your double-right-click handler.
you may want to make that global variable an object so you can track which element
registered the right click and expire specific element right clicks
accordingly. This will allow you to ignore if they double click
while moving the mouse over various objects. I consider this
optional as the chain of events are unlikely for a user to follow,
but depending on your app may result in unexpected functionality.
It might be better to define a jQuery function with this (try it):
var precision = 400;
var lastClickTime = 0;
$(document).ready(function()
{
var div = $('#div');
$(div).bind("contextmenu", function(e)
{
return false;
});
$(div).mousedown(function(event)
{
if (event.which == 3)
{
var time = new Date().getTime();
if(time - lastClickTime <= precision)
{
// DOUBLE RIGHT CLICK
alert('double click');
}
lastClickTime = time;
}
});
});
I want to know if a user stops pressing a button. So I capture the $button.mouseup(...) and $button.mouseout(...) events. However, I want the mouseout event to only matter when the user is still pressing the mouse- Otherwise, it will fire whenever the user passes over the button.
Any ideas?
Check e.which, which indicates the pressed button.
A quick and dirty method would be to use globals (or closures; some way of giving both the mouseup and the mouseout functions access to the same variable):
var mouseIsUp = true,
onMouseUp = function () {
mouseIsUp = true;
// ...
},
onMouseDown = function () {
mouseIsUp = false;
},
onMouseOut = function () {
if (!mouseIsUp) {
// ...
}
};
Is there a way to check if the space bar and at the same time track what direction the mouse is moving and how far etc.
Point of this is that I want to replicate how Photoshop scrolls when you hold the space bar, left mouse button and you move the mouse, but without having to hold down the left mouse button.
You can use keydown() and keyup() to track if the space bar is pressed or not and look at that state in your mousemove() event handler. For example:
var space = false;
$(function() {
$(document).keyup(function(evt) {
if (evt.keyCode == 32) {
space = false;
}
}).keydown(function(evt) {
if (evt.keyCode == 32) {
space = true;
console.log('space')
}
});
});
And then your mousemove() handler can see if it's pressed or not.
you will probably have to be watching for the keydown event, check to see that it's the spacebar, set a variable saying it's down, unset it when the keyup event is seen.
so, then you would look for mouse movements when that variable was set indicating the spacebar was pressed.
This is my solution:
var allowed = true;
$(document).ready(
function () {
$(document).bind('keydown', 'space', function () {
if (!allowed) return;
allowed = false;
$('#viewport').
dragscrollable();
});
$(document).bind('keyup', 'space', function () {
allowed = true;
$('#base').off('mousedown');
return false;
});
});
Works with jQuery and the Dragscrollable Plugin.