This is pretty much what I'm working on: https://jsfiddle.net/atg5m6ym/2625/
I'm animating a div with jQuery to move left, then logging to the console when I hover over the div and when I move my mouse away from it:
$("div").animate({left: '250px'}, 6000);
$('div').hover(function() {
console.log("Mouse hovered on div!");
}).mouseleave(function() {
console.log("Mouse left div!");
})
Naturally, the program will run console.log("Mouse hovered on div!"); once I put my mouse on the element.
However, if I leave my mouse idle and the animated element moves onto it, nothing in $('div').hover(function(){}) will run. I have to move my mouse onto the element for the code to run, not let the element come to the mouse.
The same thing also happens if I hover onto the element, and then leave my mouse idle. Nothing in $('div').mouseleave(function(){}) will run after the element leaves, until I move my mouse from its position.
Is there any way to work around this? I am working with animated divs and I need code to run even if the mouse is idle and the divs pass through it.
Manually take the mouse's last known position and compare it to the position of the circle. This is kind of extensive but it should get you the right results.
Here is a JSFiddle:
https://jsfiddle.net/3vpaoj59/
$("div").animate({left: '250px'}, 6000);
$(document).ready(function() {
// record down the position of the cursor
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
// boolean to know if hovered or not, and to know whether to report in console.log
var hover = false;
// function to call by setinterval to check if mouse is within radius
function checkMouse(){
// find the centerpoint of the circle by taking its position then adding half its width/height to each coordinate
var left = $("#foo").offset().left+$("#foo").width()/2;
var top = $("#foo").offset().top+$("#foo").height()/2;
// use pythagorean theorem to find distance between two points
var xdist = Math.pow(Math.abs(cursorX - left),2);
var ydist = Math.pow(Math.abs(cursorY - top),2);
var hypotenuse = Math.round(Math.sqrt(xdist+ydist));
// check if the distance is less than radius
if(hypotenuse <= $("#foo").width()/2 && !hover){
// if true and not already reported true, report then fix
console.log("mouse hovered on div!");
hover = true;
} else if (hypotenuse > $("#foo").width()/2 && hover){
// if false and not already reported false, report then fix
console.log("mouse left div!");
hover = false;
}
}
// repeatedly call this
setInterval(checkMouse, 100);
});
I changed the div's ID to "foo" for convenience. Make sure to do this as well so that the code works for your project, or modify the JS to not use "foo".
Explanation:
The reason why your problem was occurring was because your mouse's coords are only updated every time you move your cursor, and that's when hover states are checked by .hover. As such, we need to emulate the event that determines hover and call it repeatedly even when the cursor hasn't moved to make sure the hover state is updated.
Related
I'm trying to count the number of times a user scrolled the page (any direction) and moved his mouse using this jquery code:
$(window).bind('scroll',function(e){
scrolling++;
});
$(window).bind('mousemove',function(e){
mouse_moved++;
});
The problem with this is one scroll event or one mouse movement gives the variables 'scrolling' and 'mouse_moved' a very high amount instead of just incrementing it by one.
It seems whenever the scrubber / mouse position changed it is counting it as one event already, even though the original event isn't done yet.
How can I do this correctly? Count one scrolling and mouse movement event properly?
You need to track your state, e.g. detect when scrolling/moving starts, then again when it ends. And you need to decide what "ending" means — how long does the mouse have to be stationary again before you decide it's stopped moving? 5ms? 10? 15?
var scrolling = 0;
var scrollTimeout = 0;
$(window).bind('scroll',function(e){
cancelTimeout(scrollTimeout);
scrollTimeout = setTimeout(doneScrolling, 10); // 10 = 10ms
});
function doneScrolling() {
scrollTimeout = 0;
++scrolling;
}
...and similarly with the mouse move (with its own separate timer).
Is it possible to slow down the speed of a draggable element?
I have build a simple slider with jQuery drag and drop. When the slider element (the draggable element) moves to certain positions a picture fades in. So if you move the draggable element not too fast it looks like you can handle a "picture animation" with the slider. Now, I want to slow down the draggable element. So the user never can drag the element too fast.
This is an example of my code.
$('.slider').mousemove(function(){
if($(this).position().left >= 0 && $(this).position().left <= 2 ) {
$('.slider_1').fadeIn();
$('.slider_2').fadeOut();
}
...
I hope someone can help me :)
Ah! finally an interesting jQuery question.
This can definitely be achieved. Below I've explained how. If you want to go straight to the demo, click here.
Let's assume your HTML is setup as follows:
<div id="slider">
<div id="bar"></div>
</div>
Where the bar is the actual thing you click and drag.
Now what you need to do is the following:
get the $('#bar').offset().left
explicitly specify the position of #bar when the draggable is dragged, using some extra variable SPEED
For example:
ui.position.left += (ui.offset.left - ui.originalPosition.left - leftOffset)*SPEED;
Then, you can use the $('#bar').offset().left in jQuery's .fadeTo() (or other) function to change the opacity of the image you are talking about.
This all seems rather trivial, but it's not. There are some problems when trying to implement this. For example:
When the slider reaches the maximum sliding distance, it should stop animating or be reset. You can do this in multiple ways but I think the easiest solution is to write a .mousedown / .mouseup listener which updates a variable dragging, that keeps track whether the user is still trying to drag #bar. If it's not, reset #bar. If it is, keep the slider at the maximum distance until .mouseup is fired.
Also, you must be careful with predefined borders.
The code I propose is the following:
// Specify your variables here
var SPEED = -0.6;
var border = 1; // specify border width that is used in CSS
var fadeSpeed = 0; // specify the fading speed when moving the slider
var fadeSpeedBack = 500; // specify the fading speed when the slider reverts back to the left
// Some pre-calculations
var dragging = false;
var slider = $('#slider');
var leftOffset = slider.offset().left + border;
var adjustedSliderWidth = 0.5*slider.width();
// the draggable function
$('#bar').draggable({
axis: "x",
revert : function(event, ui) {
$(this).data("draggable").originalPosition = {
top : 0,
left : 0
};
$('#image').fadeTo(fadeSpeedBack, 0);
return !event;
},
drag: function (event, ui) {
var barOffset = $('#bar').offset().left - leftOffset;
if (barOffset >= 0) {
if (barOffset < adjustedSliderWidth) {
ui.position.left += (ui.offset.left - ui.originalPosition.left - leftOffset)*SPEED;
} else {
if (!dragging) { return false; }
else { ui.position.left = adjustedSliderWidth; }
}
}
// fading while moving:
$('#image').fadeTo(fadeSpeed, (ui.position.left/adjustedSliderWidth));
// remove this if you don't want the information to show up:
$('#image').html(ui.position.left/adjustedSliderWidth
+"<br \><br \>"
+ui.position.left);
}
});
// the mouse listener
$("#bar").mousedown(function(){ dragging = true; });
$("#bar").mouseup(function(){ dragging = false; });
I've also implemented the revert option on draggable so the slider nicely returns to zero when the user releases #bar. Of course you can delete this if you want.
Now the variable that your whole question is about is the variable: SPEED.
You can specify the speed of dragging by specifying a number for this variable.
E.g.:
var SPEED = 0.0; // the normal dragging speed
var SPEED = 0.5; // the dragging speed is 1.5 times faster than normal
var SPEED = -0.5; // the dragging speed is 0.5 times faster than normal
So negative values give a slower dragging speed and positive values give a faster dragging speed.
Unfortunately (or actually: fortunately), it is not possible to change the speed of the mouse pointer. This because only the OS has control over the mouse coordinates and speed. Browsers cannot influence this. Personally I think it doesn't matter: moving the slider slower than normal is what you're trying to achieve, so you can ignore the mouse pointer.
To see all this in action, I've prepared a working jsFiddle for you:
DEMO
I hope this helps you out :)
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions
I have make a div in the right of the screen. First you have a a href. You can drag this div open with this button. Here is a example: Here Right in the screen you see the "Wat is een delicous tasting" button. You can drag it open.
But i have problems with this. This are the problems:
The biggest problem. When you drag the div open. And than you drag the div back. You can drag the div outside the screen. But the is not good. When you closed the div. You can not drag it out the screen.
How can i fadein the overlay. The overlay must be smooth. Now it is not pretty.
How can i make a bounce effect in the box.
I am an beginning javascripter. I hope you can help me with this!! Thanks for helping!
You can change the code on jsFiddle: jsfiddle
Add a condition test to check whether the mouse position exceeds a certain boundary or not. If the mouse go past a fixed limit (window width - element's width), don't change the right attribute of the marker.
Fiddle: http://jsfiddle.net/ErWjr/1/
$(function () {
"use strict";
var box = $(".what-is-delicious"),
button = $(".what-is-delicious > a"),
mouseDown = false,
grabbed = 0,
start = -303,
maxLeftOffset = $(window).width() - 75;
// ^^^ Limit to 75px from the right (= marker's width)
button.mousedown(function (e) {
mouseDown = true;
$('*').bind('selectstart', false);
grabbed = e.pageX;
button.css({ cursor: "-moz-grabbing"});
$("body").append('<div class="background-overlay"></div>');
});
$('body').mouseup(function () {
mouseDown = false;
$('*').unbind('selectstart', false);
button.css({ cursor: "-moz-grab"});
$(".background-overlay").remove();
start = parseInt(box.css('right'), 10);
}).mousemove(function (e) {
if (mouseDown) {
if(e.pageX > maxLeftOffset) return; //<---- Don't go past an edge
//button.addClass("open");
box.css("right", Math.min(grabbed - e.pageX + start, 0));
}
});
});
Well, it looks like you are trying to emulate dragging rather than using the plugin designed for the purpose. Try this:
http://jqueryui.com/demos/draggable/
There are a bunch of demos there, one of those should sort you out.
I'm using the following code to allow users to resize a DIV element vertically, but when the click and drag the handle, text and other elements on the page get selected as if the user was just clicking and highlighting everything on the page. Is there a way to prevent this from happening as this looks very bad? This is being used with Prototype.js.
function DragCorner(container, handle) {
var container = $(container);
var handle = $(handle);
// Add property to container to store position variables
container.moveposition = {y:0};
function moveListener(event) {
// Calculate how far the mouse moved
var moved = { y:(container.moveposition.y - event.pointerY()) };
// Reset container's x/y utility property
container.moveposition = {y:event.pointerY()};
// Update container's size
var size = container.getDimensions();
container.setStyle({height: size.height + moved.y + 'px'});
}
// Listen for 'mouse down' on handle to start the move listener
handle.observe('mousedown', function(event) {
// Set starting x/y
container.moveposition = {y:event.pointerY()};
// Start listening for mouse move on body
Event.observe(document.body,'mousemove',moveListener);
});
// Listen for 'mouse up' to cancel 'move' listener
Event.observe(document.body,'mouseup', function(event) {
Event.stopObserving(document.body,'mousemove',moveListener);
console.log('stop listening');
});
}
Following up your earlier question and answer, add a small handle element and make it as the only element that can be selected and draggable. Also I guess you made that div's position as relative and handle position as absolute. Right??
Adding the following to the DIV fixed this:
onselectstart="return false;"