I am trying to detect if mouse is hovering over some element with Javascript by using mouse coordinates and element position (note that I'm not able to use hover event). For that I use this function:
var rect = $('.rectangle'),
rectLeft = rect.offset().left,
rectTop = rect.offset().top,
rectRight = rect.offset().left + rect.width(),
rectBottom = rect.offset().top + rect.height();
if (rectLeft < e.pageX
&& rectRight > e.pageX
&& rectTop < e.pageY
&& rectBottom > e.pageY) {
// in
}
else {
// out
}
While it works flawlessly in Chrome, I have some issues in IE11 (didn't try lower versions), where detection is not exact - the right border of element and pageX position of mouse differs. You can see the behavior in this snippet:
http://codepen.io/Jarino/pen/qdywGv
When you go with the mouse into the area from right border, the area doesn't turn green immediatley, but after some more pixels.
Thanks for any advice.
EDIT
This seems to be the problem specific to only my machine, which it's pretty weird. I tried this on another company computer and it works, also as Infira commented, it works on his enviroment too.
Related
I have built a javascript application for dragging and dropping divs from one place to another in the same page. I have made the dragging part. I have the co-ordinates of the div(s) where I must drop the div but I am stuck at the part where I should introduce conditions for matching the divs at target zone. Basically the divs can be dropped above any of the divs but they must drop exactly above the target div if on onmouseup event I am anywhere close to that target div. I am thinking of assigning the top and left attribute of my dragged(onmousdown) div to the target div but I may be wrong.. Please guide my through this part.
Here is the part where I need help:
function mouseUp(e)
{
e = e || window.event;
var mousePos = mouseCoords(e);
var itemPosition = getPosition(id);
//console.log("This is at: "+itemPosition);
//console.log(mousePos);
console.log(getPosition(id));
for(var i=0;i<destination.length;i++)
{
var curTarget = destination[i];
var targPos = getPosition(curTarget);
var targWidth = parseInt(curTarget.offsetWidth);
var targHeight = parseInt(curTarget.offsetHeight);
var temp = document.elementFromPoint(event.clientX, event.clientY);
}
id = null;
}
Here is the link to my code: jsfiddle The javascript part must be written inside of html to make it work properly
The question title is misleading, what you really seem to be having trouble with is finding the coordinates of the target divs. You're grabbing mouse coordinates just fine using clientX and clientY though you likely want to be using the pageX and pageY coordinates as they are relative to the rendered page and not the viewport (ie. window the user is looking at). 0,0 using the client coordinates will change as the user scrolls whereas the page coordinates will reference a particular spot on the webpage.
As for finding your drop divs you can use the method getClientBoundingRect on the element and use the top, right, bottom, and left properties on the returned object to determine if the pageX and pageY coordinates of the mouse are inside (or close to inside) the element.
Maybe there's a better way, but this is how I would do it.
function mouseUp(e){
var targets = document.getElementsByClassName("drop_here");
for(var i=0;i<targets.length;i++){
var bounds = targets[i].getClientBoundingRect();
var lenience = 5;
if(e.pageX < bounds.right + lenience &&
e.pageX > bounds.left - lenience &&
e.pageY < bounds.top - lenience &&
e.pageY > bounds.bottom + lenience){
//do my work here
}
}
}
I am trying to show a popup message for users when they are trying to leave the page by moving their mouse to the top of the window.
The issue I've faced with is that seems like internet explorer can't identify mouseleave event specifically for situation when mouse moves to the top. Instead it sets pointer coordinates clientX and clientY to '-1' in all cases of mouse moving outside the window to the top, bottom, left and right.
Need to mention that in case of moving mouse outside the window to the right (to fire the event browser should not be maximized on full screen) it sets clientY to '-1' from time to time. if you move your mouse to the left/right 20 times you will get 30% of clientY = '-1' and for rest % clientY will contain appropriate value.
I use the following code:
$(document).mouseleave(function(e){console.log("clientX: " + e.clientX + " clientY: " + e.clientY)});
Is there any way to identify mouse leave specifically on the top ? Thank you very much for any answer :)
You can use this, IE there is some Off on the value of y
if(navigator.userAgent.toLowerCase().indexOf("trident")>-1){
document.captureEvents(Event.MOUSEMOVE)
document.onmousemove = getMouseXY;
var tempX = 0;
var tempY = 0;
function getMouseXY(e) {
tempX = event.clientX + document.body.scrollLeft;
tempY = (event.clientY + document.body.scrollTop);
if(tempY <= 5)
{
// your code will be here
}
}
}
When a user is on a touch screen device, I'd like to restrict diagonal scrolling - so the idea is to force scrolling one direction at a time - horizontal or vertical.
I've set up a JS Fiddle that detects if touch scrolling is enabled and I'm able to output the x and y coordinates. But I don't see an offset or anything and figure I need that to calculate the intended direction.
I know that apple uses a directionalLockEnabled that will restrict, so I'm wondering if something like this is available in Kendo. If not, maybe there's a way I can figure out which direction the user is intending to scroll in and 'freeze' the other coordinate.
A JS fiddle I created (relevant part in the dataBound method):
http://jsfiddle.net/dmathisen/tskebcqp/
(the relevant code only works on touch... but should work if you enable mobile emulation in dev tools)
Another issue is the amount of times the scroll event is triggered. When working, maybe I can set up a debounce to handle how often it's triggered.
If you want to use javascript for this fix, you can calcul the ranges of the X and Y moves.
For that with touch devices, set the start posi X and Y when touchstart and calcul the distances when touchmove
var touchY = touchX = 0;
$(document).delegate('.yourWrap', 'touchstart', function(e){
touchX = e.originalEvent.touches[0].pageX;
touchY = e.originalEvent.touches[0].pageY;
});
$(document).delegate('.yourWrap', 'touchmove', function(e){
if (Math.abs(touchX - e.originalEvent.touches[0].pageX)
> Math.abs(touchY - e.originalEvent.touches[0].pageY)) {
// Block overflow-y
} else {
// Block overflow-x
}
touchX = e.originalEvent.touches[0].pageX;
touchY = e.originalEvent.touches[0].pageY;
});
For wheel devices, compare delta
(e.wheelDeltaY/3 || -e.deltaY)
(e.wheelDeltaX/3 || -e.deltaX)
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 need to calculate the position, height and width of every anchored link in my page. I know how to find the x,y coords, but I have a problem with the height and width. The problem appears when the link has children inside (images, divs etc), so heightOffset and widthOffset won't work. Is there a way to do this without going on all the children and calculating their sizes?
EDIT:
Here is some code to demonstrate what I mean (the press function is called whenever the mouse is being pressed):
function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
return [curleft,curtop];
}
function getHeight(elem) {
if (elem.style.pixelHeight) {
return elem.style.pixelHeight;
} else {
return elem.offsetHeight;
}
}
function getWidth(elem) {
if (elem.style.pixelWidth) {
return elem.style.pixelWidth;
} else {
return elem.offsetWidth;
}
}
function press(e)
{
x= e.pageX;
y= e.pageY;
window.alert(x+","+y);
var links = document.getElementsByTagName('a');
for (i = 0; i < links.length; i++){
var pos = findPos(links[i]);
window.alert(x+","+y+" "+pos[0]+" " + pos[1] + " "+links[i].offsetWidth+ " "+links[i].offsetHeight);
if (x >= pos[0] && x <= pos[0] + getWidth(links[i]) && y >= pos[1] && y <= pos[1] + getHeight(links[i])){
window.alert(links[i].href);
i = links.length;
}
}
}
When I encounter a link with an image for instance it doesn't return me the right size.
Thanks
offsetWidth/Height do very much work on links that contain images, as long as you haven't done anything weird like overflowing or positioning the images or other child content so that they fall out of the content area of their parent.
Your code isn't using offsetHeight on IE, it's using pixelHeight, which doesn't do what perhaps you think it does. Stick with offsetHeight.
Conversely, you are using event.pageX/Y, which is a non-standard extension IE doesn't have. Sadly the only reliable way to get page-relative co-ordinates from an event is to use clientX/Y and adjust for viewport scrolling.
I don't really know why you are going to the effort of enumerating link positions when for a mouse click/down event you can quite reliably get the element that was clicked on using event.target/srcElement. In fact this is the only reliable way to do it. Consider a link that has split over two text lines. Now what you've got is a non-rectangular region; you can't test whether a particular mouse position lies within that area using a simple x and y range test.
The correct properties are offsetHeight (not heightOffset) and offsetWidth (not widthOffset).
Those properties should correctly return the sizes you're after, because the children would expand the elements to fit, assuming overflow is set to visible. There's no need to calculate the sizes of the children in any situation.
offsetHeight and offsetWidth aren't part of any standard but most browsers seem to have them implemented anyway.
Since you're having problems with Safari and offsetHeight, maybe you could try the getClientRects() method:
http://www.quirksmode.org/dom/tests/rectangles.html
var dims = links[i].getClientRects()[0];
var width = dims.right - dims.left;
var height = dims.bottom - dims.top;
Can't say I've ever used getClientRects(), however. It sounds like the results may be closer to clientWidth and clientHeight.
FURTHER EDIT
I figured out a workaround. The following does not work:
<a href="#">
<img onclick="press(event);" src="http://sstatic.net/so/img/logo.png" alt="" />
<!-- onclick handler alerts with size 250x15 -->
</a>
But wrapping a <span> tag around the <img> tag, like so:
<a href="#"><span>
<img onclick="press(event);" src="http://sstatic.net/so/img/logo.png" />
<!-- onclick handler alerts with size 250x61 -->
</span></a>
Fixes the problem. At least, it does in Chrome but like I said before Chrome and Safari share the WebKit rendering engine, so it should work for Safari too.
You should not use the values in elem.style.* to determine the size of an element. These values are CSS styles and aren't reliable. Use only offsetWidth and offsetHeight.
To get the position of an element, use the answers to this question: Retrieve the position (X,Y) of an HTML element