I'm writing tests and trying to simulate a "mousemove" event. The method I am using which works in Chrome, Firefox, Safari, and IE 10 & 11 is:
var e = new MouseEvent('mousemove',{
"clientX": 250,
"clientY": 100,
});
myElem.dispatchEvent(e);
But it does not work in Edge. The "mousemove" event fires and is caught by my listener, but the position is incorrect. Instead of using the provided coordinates, it appears to use the window origin, 0,0.
My actual code does runs correctly in Edge, so it appears to solely be an issue with simulating the event. But the added complication is this is for a d3 chart and the mouse position is being read with d3.mouse, so I cannot rule out that there is something different in Edge in the interaction between d3.mouse and a mouse event.
Other approaches I have tried include using a CustomEvent and using a PointerEvent, but both seemed to trigger the eventListener, but not even be readable by d3.mouse.
UPDATE
Originally I thought that the specified coordinates were completely ignored; this is not the case. The reality is even more bizarre. If I use absurdly high numbers, then I can get it to register over my element. But real numbers are considered waaay off screen.
For example, if my element getBoundingClientRect gives me:
left: 100,
top: 10,
width: 500,
height: 300
and I use coordinates such as:
var e = new MouseEvent('mousemove',{
"clientX": 350,
"clientY": 150,
});
which should place my cursor over the element, Edge seems to think my cursor it is way off screen. If instead I put in numbers such as:
var e = new MouseEvent('mousemove',{
"clientX": 100000,
"clientY": 50000,
});
Edge will then consider this to be over my element.
The d3.mouse method returns the x,y coordinates of the mouse event relative to the graph container. The clientX and clientY values you are using to simulate the mouse event provide the x,y coordinates of the mouse event relative to the current window. So, the coordinate sets are not the same. You can manually calculate the same coordinate values as the d3.mouse method via:
d3MouseX = clientX - rect.left
d3MouseY = clientY - rect.top
where rect.left and rect.top are the coordinates of the bounding rectangle for the graph object. You can get these coordinates with the e.target.getBoundingClientRect() method.
Related
I have a <div> on a webpage with the following dimensions:
Using Javascript/jQuery I get the following position and dimensions of that element:
$elem.offset()
{top: 1434.4791564941406, left: 32.222225189208984}
$elem.outerWidth()
930
$elem.outerHeight()
536.788
It seems to me that a MouseEvent contains clientX and clientY (or pageX, pageY) coordinates in "number" type.
Question: Why is it that a onmouseenter event fires with a clientX value of 31 or 32 (depending on how quickly I move the mouse), both of which should be outside of the element’s border box.
Question: Converting floats to integers probably isn’t a good idea because of rounding. So, how do I go about checking the border box here: convert the mouse coordinates to floats? Meaning, that a (1434, 32) mouse coordinate is just outside whereas (1435, 33) is barely inside of the bounding box?
Here is a fiddle showing an example of what I'm trying to do. (I know it doesn't look right but it just needs some changes and that isn't the problem I'm facing :p ).
Im creating a pie chart using Raphael SVG, and the tooltip is also an svg element.
draw_tooltip(SVGpaper, this, 0);
is used to clear the tooltip.
The problem is I don't understand how to properly handle the mouseover event. On each event the tooltip needs to popup after clearing the previous tooltip, which I've tried to manage using the counter. But as is apparent from the fiddle, the mouseover event isn't smooth. Also, it stays even while shifting to other arcs and when it moves out of the pie.
Pleae suggest some solution!
I suspect the problem you are having, is that the new path/element that is being displayed for the tooltip, is then interfering with the mouse events, stopping the event from working. So Raphael can be a bit fiddly for mouse events, if dragging/moving. There's probably a couple of different ways around it. One may be handling events more globally and deciding what to do with them, or if you don't mind it, move the tooltip a bit further from the cursor location.
arc.mouseover(function (e) {
x = e.pageX + 50;
y = e.pageY;
draw_tooltip(this, 1, display_text, x, y);
});
arc.mouseout( function(e) {
popup.remove();
popup_txt.remove();
transparent_txt.remove();
});
arc.mousemove( function(e) {
popup.attr({ x: e.pageX - 70, y: e.pageY - 70 });
popup_txt.attr({ x: e.pageX - 25, y: e.pageY - 45});
transparent_txt.attr({ x: e.pageX - 120, y: e.pageY - 120 });
});
}
I've also changed the path for a rect and a couple of bits, but the main thing is keeping the tooltip away from the event location. Otherwise I wonder if you may need to handle it from jquery or possibly to a handler thats attached to other elements than the arc, which will depend on the complexity of the page maybe. See if this solution will do.
Fiddle here http://jsfiddle.net/74YNb/13/ (text alignment may need tweaking for all browsers)
Using canvas and mousemove I create a masking effect.
Example: FIDDLE
The masking effect works but on fast scrolling performance isn't ideal.
How can I improve the framerate?
I fixed it simply by using the window mouse coordinates, instead of the listener on the canvas (assuming you want the picture to just be black).
http://jsfiddle.net/gfZ5C/166/
I also changed to requestAnimationFrame, you'll notice a complete FPS difference in the movement of the circle, instead of it moving according to the listener.
window.onmousemove = function (e) {
circle.posX = e.pageX-can.offsetLeft;
circle.posY = e.pageY-can.offsetTop;
circle.hide = (circle.posX >= 550 || circle.posY >= 550) ? true : false;
}
if (!circle.hide) ctx.arc(circle.posX, circle.posY, 70, 0, Math.PI * 2, true);
I left it at 550, so that you could see it actually disappear, you can change it to a big number if you want the circle to just drag right off the canvas.
Also there is no lag on the circle following the mouse now.
Update:
Fixed the fiddle so that the circle adjusts for window offset too.
The offset is relevant to its parent element, so depending on how far deep your canvas is, you will have to subtract each elements offset that it is inside.
Update:
Switched to handle 'onmouse' events, this will work much better on a real site, because mousing over the iFrame doesn't work well, but it still works. Will work 100% as intended on a real site.
In IE 7, 8, 9, chrome, and firefox the pageX/Y property on a mouseHandler refers to the position relative to the top of the page, while the clientX/Y property gives the position relative to the current viewport. In IE 10, it looks like pageX/Y is the same as clientX/Y. Is there a known work around?
You can experiment with this http://jsfiddle.net/FCTUW/2/ just scroll to the bottom of the page in the bottom right and move your mouse over the grey rectangle.
Here is the code used to find the coordinates since SO wants code...
canvas.mousemove(function(e){
var pageCrds = '('+ e.pageX +', '+ e.pageY +')',
clientCrds = '('+ e.clientX +', '+ e.clientY +')';
Does anyone know why this change was made, or how to get the correct page coordinates?
I'm not seeing the same results you are. You may not be viewing the actual results of your script - or perhaps you accidentally wrote the same property twice. Either way, the results I have below are from Internet Explorer 10, on Windows 8, running your demo.
This is in line with what MSDN states regarding client and page values:
Client coordinates do not reflect the scroll offset of the page. To get the mouse pointer's coordinates relative to the upper-left corner of the document, use the pageX and pageY properties.
I'm moving the mouse over a div and I want to know the mouse coordinates with respect to the div origin. (upper left corner)
I expected the mousemove event to contain the relative (client?) coordinates of the mouse, but apparently it doesn't.
In firefox for instance, none of the event properties* contain relative coordinates
Am I missing something?
*clientX,Y - pageX,Y - screenX, y
You're not missing anything, but you'll need to calculate the relative coordinates yourself.
Something along these lines should do it (substitute jquery with w/e code you want to use to get the position):
var pos = $('div').position();
var relX = event.pageX - pos.left;
var relY = event.pageY - pos.top;
Also see: JS: mouse coordinates relative to an element which covers some of the details on supporting other browsers (though if you're using jquery that may not be needed).