I want a function to be called regularly at a given interval whilst the left mouse button is being held down over a specific element. Is there a simple way of doing this in jQuery or should I use vanilla javascript and setInterval/setTimeout?
Thanks
Here's a jQuery plugin that provides a mousehold event.
http://remysharp.com/2006/12/15/jquery-mousehold-event/
If you go to the demo page and click on one of the arrows to the right of the last input box you'll see how it works.
This is how I would do it:
HTML:
<div id="box"></div>
JavaScript:
var box = $('#box'),
iv;
function foo() {
box.append('*');
}
box.bind('mousedown mouseup', function(e) {
$(this).toggleClass('hold', e.type === 'mousedown');
});
iv = setInterval(function() {
box.hasClass('hold') && foo();
}, 1000);
So you bind a handler to both the mousedown and mouseup events, and set the hold CSS class accordingly. Meanwhile, an independent timer iv will inspect whether or not the hold class is set, and call your function (foo) accordingly.
Live demo: http://jsfiddle.net/simevidas/7CUFE/
jQuery does not provide any function watching support as a result, you could use the vanilla setTimeout function as follows:
var timer;
function functionToRun() {
// Function code here...
functionToRun();
}
var inFunction = function() {
timer = window.setTimeout(functionToRun, intervalToRunFor);
}
var outFunction = function() {
window.clearTimeout(timer);
}
$('selector').hover(function() { inFunction, outFunction }
var mouseDown = false;
$('#yourID').bind('click', function() {
mouseDown = true;
});
$('#yourID').bind('mouseup', function() {
mouseDown = false;
});
setInterval('checkOut();',5000);
function checkOut() {
if(mouseDown) alert('mouse is down! Whatup!');
});
Related
I am currently working on a javascript module which open and close boxes, tooltip or similar, the function works great the only problem is when I call it twice on a page where the 'boxes' classes are different the window mouseup event will be overwritten and only one of the two module instances of boxes can now be closed after opening them.
var boxRevealer = (function () {
var buttons;
var boxes;
var element;
var drp_active = false;
var boxConstruct = function (btns, bxs) {
buttons = document.querySelectorAll(btns);
boxes = document.querySelectorAll(bxs);
boxEvents();
};
var boxEvents = function () {
buttons.forEach(function (e) {
e.addEventListener("click", function (ee) {
element = document.getElementById(e.getAttribute("data-drp"));
element.classList.toggle("displayn");
drp_active = true;
});
});
window.addEventListener("mouseup", function (e) {
if (drp_active === true) {
if (!e.target.classList.contains("filt_holy")) {
boxes.forEach(function (e) {
console.log("ELEMENT");
console.log(e);
e.classList.add("displayn");
});
}
}
}, false);
};
return {
boxConstruct: boxConstruct,
boxEvents: boxEvents
};
})();
Here is how i call the module
window.addEventListener("load", function(e){
boxRevealer.boxConstruct(".head_drp_btn", ".head_drp");
boxRevealer.boxConstruct(".mkt_drp_btn", ".mkt_drp");
});
So my question is, should I always name the boxes the same, or is there a work around?
Just remove the event before adding it, I think the same event is getting called twice.
So updated code will be as follows:
// Attach an event handler to <div>
e.addEventListener("mousemove", myFunction);
// Remove the event handler from <div>
e.removeEventListener("mousemove", myFunction);
And remove the window event as well before adding it.
I made a control (numeric spinner up and down), to work in a table:
JSFIDDLE: http://jsfiddle.net/Leandro1981/wn8vd/1/
and I want simulate the "mousedown, increment while mouse button is helding" but I can't do it. I tried to mix it with the following and functional script:
JSFIDDLE: http://jsfiddle.net/Leandro1981/kKW85/
but I couldn't make it.
My last attempt here:
http://jsfiddle.net/Leandro1981/S8Zt9/1/
Maybe the wrong is the
timeout = setInterval(function () {
But I couldn't figure out. I'm using bootstrap 3, so I can't use some JQuery UI plugins...
Any help will be preciated!
Please comment below if you have any question, comment or anything to improve this question, and sorry for my english :)
Please be free to use my code/control in any way.
Thanks and kind regards
Write a factory to set up each control so you get a closure over the variables, now it's just a matter of being able to make it work given the relevant elements. For this, you'll need to
Listen for mousedown on the up and down nodes to set off the changes
Start a timeout loop to keep doing your change
Listen for mouseup on window to ensure you cancel the timeout loop (you may also want to listen for mouseout/loss of focus)
So all together,
function spinFactory(node, up, down) { // I wrote this vanilla :D
var spinning, delta;
window.addEventListener('mouseup', stopSpin);
function spin() {
node.value = +node.value + delta;
spinning = setTimeout(spin, 500);
}
function stopSpin() { // maybe also invoke this on mouseout/loss of focus
window.clearTimeout(spinning);
delta = 0;
}
up.addEventListener('mousedown', function spinUp() {
delta = 1;
spin();
});
down.addEventListener('mousedown', function spinDown() {
delta = -1;
spin();
});
}
// apply to your control, used a bit of jQuery to make life easier
$('.PNET-spinner').each(function () {
spinFactory(
this.getElementsByTagName('input')[0],
$(this).find('.btn:first-of-type')[0],
$(this).find('.btn:last-of-type')[0]
);
});
DEMO
I have updated the Fiddle here ... Please check this and it might helps you..
Script
$('.PNET-spinner .btn:first-of-type').on('mousedown', function (e) {
var timer, proxy = this;
timer = setInterval(function () {
increment(proxy);
}, 200);
$(document).one("mouseup", function () {
increment(proxy);
if (timer) clearInterval(timer);
});
});
$('.PNET-spinner .btn:last-of-type').on('mousedown', function () {
var timer, proxy = this;
timer = setInterval(function () {
decrement(proxy);
}, 200);
$(document).one("mouseup", function () {
decrement(proxy);
if (timer) clearInterval(timer);
});
});
function increment(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
$(numupdown).val(inputValue);
}
function decrement(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
if (inputValue > 1) {
inputValue--;
$(numupdown).val(inputValue);
}
}
You simply need to take care of two things. First, your function to increment and decrement the value in the textbox should be called again and again till user do mouseout or mouseup. Second, make surethis has the right value in var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
Following code shows how to do it for the increment button. Similar thing, you can implement for decrement button.
var timeout;
var inc = function () {
var myThis = this;
var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
console.log(inputValue);
$(numupdown).val(inputValue);
clearTimeout(timeout);
timeout = setTimeout(function(){
//http://stackoverflow.com/questions/3630054/how-do-i-pass-the-this-context-to-a-function
inc.apply(myThis, arguments);
}, 1000);
};
var incStop = function(){
clearTimeout(timeout);
}
$('.PNET-spinner .btn:first-of-type').on('mousedown', inc);
$('.PNET-spinner .btn:first-of-type').on('mouseup', incStop);
$('.PNET-spinner .btn:first-of-type').on('mouseout', incStop);
Check this DEMO here.
I am playing around with a short little code to see if I can get a function going while the user has their mouse down and then end it when they bring their mouse up. For this example I am trying to increment a number that I am displaying on the screen as the user moves their mouse while holding the button down. I want it to freeze and stop once they release the button, however the counter just resets and the count continues from 0 even though the button is not being pressed...
function dragInit(state, e) {
var i = 0;
$(document).on("mousemove", function() {
if (state) {
i+=1;
$('#debug').text(i); //Show the value in a div
}
});
}
$(document).ready(function() {
$(document).on(
{mousedown: function(e) {
var state = true;
dragInit(e, state);
},
mouseup: function(e) {
var state = false;
dragInit(e, state);
}
});
});
As an aside, is there a way I can display whether a variable is true or false onscreen? When I try it just says [object Object].
There are a lot of mistakes in your code. I suggest you to read more basic concepts before starting to use jQuery.
The order of the parameters passed to dragInit() is wrong on both mouseup and mousedown event bindings.
The reason your counter is restarting is because your variable i is local, so it exists only during the function context it is declared in.
You are making the same mistake with the state variable, but in this case it is completely unnecessary to declare it.
Consider making your counter a global (even though it is not a good practice).
I can't provide you code because I am answering from my phone. A solution would be create a mousemove event that checkes whether the mouse button is pressed before incrementing your counter.
Hope I helped
You could do something like this:
function dragInit() {
$(document).on("mousemove", function () {
if (eventState.state) {
eventState.count += 1;
$('#debug').text(eventState.count); //Show the value in a div
}
});
}
// Create an object to track event variables
var eventState = {
count:0, //replaces your previous 'i' variable
state: false //keeps track of mouseup or mousedown
};
$(document).ready(function () {
$(document).on({
mousedown: function (e) {
eventState.state = true;
dragInit(); //don't need to pass anything anymore
},
mouseup: function (e) {
eventState.state = false;
dragInit(); //don't need to pass anything anymore
}
});
});
jsFiddle
Or keep everything together as one object
var dragInit = function () {
var count = 0;
var state = false;
var action = function () {
$(document).on("mousemove", function () {
if (state) {
count += 1;
$('#debug').text(count); //Show the value in a div
}
})
};
$(document).on({
mousedown: function (e) {
state = true;
action(); //don't need to pass anything anymore
},
mouseup: function (e) {
state = false;
action(); //don't need to pass anything anymore
}
});
}
$(document).ready(function () {
var obj = new dragInit();
});
jsFiddle 2
Example in response to comment
jsFiddle: This shows why the following code snippets differ in execution.
// Works
$(document).on("mousemove", function () {
if (state) {
}
})
// Doesn't
if (state) {
$(document).on("mousemove", function () {
});
}
Less code, You just need this.
Use jquery on and Off to turn on and off mousemove event.
Counter Reset http://jsfiddle.net/kRtEk/
$(document).ready(function () {
var i = 0;
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').text(i++); //Show the value in a div
});
},
mouseup: function (e) {
i = 0;
$('#debug').text(i);
$(document).off("mousemove");
}
});
});
W/O Reset http://jsfiddle.net/gumwj/
$(document).ready(function () {
var i = 0;
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').text(i++); //Show the value in a div
});
},
mouseup: function (e) {
$(document).off("mousemove");
}
});
});
WithNoCounter http://jsfiddle.net/F3ESx/
$(document).ready(function () {
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').data('idx',parseInt($('#debug').data('idx')|0)+1).text($('#debug').data('idx')); //Show the value in a div
});
},
mouseup: function (e) {
$(document).off("mousemove");
}
});
});
Assuming you are married to Jquery (nothing wrong with that) - check out and consider entirely re-thinking your approach leveraging the ".one()" (http://api.jquery.com/one/) method.
edit: and if that taste doesn't sit well - familiarize yourself with the "deferred" object (http://api.jquery.com/category/deferred-object/)
lots of ways to approach this via jquery - what you decide in the end depends on what you really intend to do with this.
I was wondering if there is a function to be run after an element (e.g. div class="myiv") is hovered and check every X milliseconds if it's still hovered, and if it is, run another function.
EDIT: This did the trick for me:
http://jsfiddle.net/z8yaB/
For most purposes in simple interfaces, you may use jquery's hover function and simply store in a boolean somewhere if the mouse is hover. And then you may use a simple setInterval loop to check every ms this state. You yet could see in the first comment this answer in the linked duplicate (edit : and now in the other answers here).
But there are cases, especially when you have objects moving "between" the mouse and your object when hover generate false alarms.
For those cases, I made this function that checks if an event is really hover an element when jquery calls my handler :
var bubbling = {};
bubbling.eventIsOver = function(event, o) {
if ((!o) || o==null) return false;
var pos = o.offset();
var ex = event.pageX;
var ey = event.pageY;
if (
ex>=pos.left
&& ex<=pos.left+o.width()
&& ey>=pos.top
&& ey<=pos.top+o.height()
) {
return true;
}
return false;
};
I use this function to check that the mouse really leaved when I received the mouseout event :
$('body').delegate(' myselector ', 'mouseenter', function(event) {
bubbling.bubbleTarget = $(this);
// store somewhere that the mouse is in the object
}).live('mouseout', function(event) {
if (bubbling.eventIsOver(event, bubbling.bubbleTarget)) return;
// store somewhere that the mouse leaved the object
});
You can use variablename = setInterval(...) to initiate a function repeatedly on mouseover, and clearInterval(variablename) to stop it on mouseout.
http://jsfiddle.net/XE8sK/
var marker;
$('#test').on('mouseover', function() {
marker = setInterval(function() {
$('#siren').show().fadeOut('slow');
}, 500);
}).on('mouseout', function() {
clearInterval(marker);
});
jQuery has the hover() method which gives you this functionality out of the box:
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
},
function () {
// the element is no longer hovered... do stuff
}
);
To check every x milliseconds if the element is still hovered and respond adjust to the following:
var x = 10; // number of milliseconds
var intervalId;
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
intervalId = window.setInterval(someFunction, x);
},
function () {
// the element is no longer hovered... do stuff
window.clearInterval(intervalId);
}
);
DEMO - http://jsfiddle.net/z8yaB/
var interval = 0;
$('.myiv').hover(
function () {
interval = setInterval(function(){
console.log('still hovering');
},1000);
},
function () {
clearInterval(interval);
}
);
Can anybody help me on this one...I have a button which when is hovered, triggers an action. But I'd like it to repeat it for as long as the button is hovered.
I'd appreciate any solution, be it in jquery or pure javascript - here is how my code looks at this moment (in jquery):
var scrollingposition = 0;
$('#button').hover(function(){
++scrollingposition;
$('#object').css("right", scrollingposition);
});
Now how can i put this into some kind of while loop, so that #object is moving px by px for as #button is hovered, not just when the mouse enters it?
OK... another stab at the answer:
$('myselector').each(function () {
var hovered = false;
var loop = window.setInterval(function () {
if (hovered) {
// ...
}
}, 250);
$(this).hover(
function () {
hovered = true;
},
function () {
hovered = false;
}
);
});
The 250 means the task repeats every quarter of a second. You can decrease this number to make it faster or increase it to make it slower.
Nathan's answer is a good start, but you should also use window.clearInterval when the mouse leaves the element (mouseleave event) to cancel the repeated action which was set up using setInterval(), because this way the "loop" is running only when the mouse pointer enters the element (mouseover event).
Here is a sample code:
function doSomethingRepeatedly(){
// do this repeatedly when hovering the element
}
var intervalId;
$(document).ready(function () {
$('#myelement').hover(function () {
var intervalDelay = 10;
// call doSomethingRepeatedly() function repeatedly with 10ms delay between the function calls
intervalId = setInterval(doSomethingRepeatedly, intervalDelay);
}, function () {
// cancel calling doSomethingRepeatedly() function repeatedly
clearInterval(intervalId);
});
});
I created a sample code on jsFiddle which demonstrates how to scroll the background-image of an element left-to-right and then backwards on hover with the code shown above:
http://jsfiddle.net/Sk8erPeter/HLT3J/15/
If its an animation you can "stop" an animation half way through. So it looks like you're moving something to the left so you could do:
var maxScroll = 9999;
$('#button').hover(
function(){ $('#object').animate({ "right":maxScroll+"px" }, 10000); },
function(){ $('#object').stop(); } );
var buttonHovered = false;
$('#button').hover(function () {
buttonHovered = true;
while (buttonHovered) {
...
}
},
function () {
buttonHovered = false;
});
If you want to do this for multiple objects, it might be better to make it a bit more object oriented than a global variable though.
Edit:
Think the best way of dealing with multiple objects is to put it in an .each() block:
$('myselector').each(function () {
var hovered = false;
$(this).hover(function () {
hovered = true;
while (hovered) {
...
}
},
function () {
hovered = false;
});
});
Edit2:
Or you could do it by adding a class:
$('selector').hover(function () {
$(this).addClass('hovered');
while ($(this).hasClass('hovered')) {
...
}
}, function () {
$(this).removeClass('hovered');
});
var scrollingposition = 0;
$('#button').hover(function(){
var $this = $(this);
var $obj = $("#object");
while ( $this.is(":hover") ) {
scrollingposition += 1;
$obj.css("right", scrollingposition);
}
});