I have an angular directive wrapped around a D3 graph. I have created a tooltip and i handle the visibility in 'mouseover' and 'mouseout' of the parent element, i also handle the tooltip position in 'mousemove' so that it moves with the mouse.
The tooltip is absolute.
The issue is, when i move my mouse pointer fast enough, the mouseout event of the parent gets called , even though the mouse pointer is still within the specified area. I logged and found out , it is happening because sometimes the mouse pointer (when moving fast, the tooltip position hasn't updated so quick) hovers over the tooltip , which is absolutely positioned and not part of the parent.
This creates some difficulties as on mouseout of the parent element i am also changing the visibility of another element, so it gives a fluctuating/flicker kind of effect on fast mouse move.
I am not sure whether this is the expected behavior or if it is specific to D3 or angular.
Here is a fiddle:
http://jsfiddle.net/6bQA8/5/
initially the text and polylines are shown, they would hide when hovered over any of the pie slices.
on hover over any of the pie slices, you will get a tooltip, if you move your mouse, the tooltip also moves, if you move your mouse fast enough, check the console and you will see "tooltip hovered" ,also on the UI you would see the flickering text and polylines which should be visible on mouseout from the slices.
In ideal case, "tooltip hovered" should never be called as the tooltip always updates with the mouse and it is not below the pointer.
P.S: one way to solve the problem is to add pointer-events:none to the tooltip or to increase the offset of tooltip from the pointer, but i am more interested in knowing why this happens and if this is a limitation of the framework or the browser or something wrong in the code. Also, since i am re-using the same tooltip object later for clicking purpose, so at that time i would have to remove the pointer-events:none, and increasing the offset does not look really good in the UI. Also, both these methods are actually hacks and not probably the correct solution.
Since you are asking a solution apart from the pointer-events:none i have done it this way:
slices.on("mouseout", function(d) {
//return if the mouse out is triggered by the tooltip-menu
if(d3.select(d3.event.toElement).classed("tooltip_menu")){
return;//if the to element is tooltip_menu
}
working fiddle here
Javascript can not block mouse until it does all calculations and DOM manipulations, that's why, there is dealy in moving the tooltip.
In modern browsers operations happens at least with 4ms delay, as setTimeout/setInterval minimum delay is 4ms.
Related
I am trying to display a heatmap of where the user moved their mouse on a screen (using a Chrome extension). I'm using a library called heatmap.js to handle this.
More specifically, I am using this as an example -- https://www.patrick-wied.at/static/heatmapjs/example-mousemove-heatmap.html
My problem is that the site I wish to display this heatmap on is making heavy use of z-index. The issue with this is that when you mouseover an element with a z-index other then auto, the value returned by onmousemove is not what one would expect -- instead of the value of the mouse on the screen, some other value relative to the top left of the screen is returned.
You can see this in action here -- https://jsfiddle.net/rj870o6c/
To counteract this, I tried adding an overlay div on top of the entire page with a z-index of 9999. This works, but then I lose the ability to interact with the page below, and of course, I can not use pointer-events: none; since I need to capture the value of the mouse.
You can see this in action here (try clicking the link in the yellow box, it won't work) -- https://jsfiddle.net/ktwbbpbn/
Is there a way to get the real value of the mouse pointer when hovering over elements that have a z-index?
Any help would be greatly appreciated.
So it turns out that the issue was that I was using layerX and layerY for grabbing the position of the mouse. That's a bad idea for my use case because that only returns data relative to the current layer (https://developer.mozilla.org/en/docs/Web/API/UIEvent/layerX). The answer is to use pageX and pageY instead. See this for more info.
For anyone who might find this useful, here's a JSFiddle with everything working as expected -- https://jsfiddle.net/h1us1syr/
I have a multiline chart using D3, and the lines have nodes to mark the points. I also have legends below x-axis to display or hide each line when a user clicks on them. Similar to this example
The chart and legend selection works totally fine when I click normally on legends. But when I click rapidly on legends, one of the lines' nodes disappear. When I inspected the page, I found they got relocated to the top of the browser window(and not visible because there's no svg element there)
I don't even know what the problem is and where should I start debugging as it works fine with normal speed mouse clicks on legends.
I know it is very difficult for anyone to help without looking at the source code or a working fiddle, but I just wanted to know (before I try to reproduce the problem on fiddle) has anyone experienced something like this before? does mouse clicking speed affect how elements get rendered in D3? or this is not a D3 problem at all and some javascript/dom thing I am overlooking?
Some "strange" behaviour can occur depending on how your transitions are set up. For example, if there are many transitions attached to the same element, one might be interrupted when another one starts, and that may result on some element not being redrawn on screen.
For more about this see D3 documentation: Working with transitions, specifically this section which explains that "for a given element, transitions are exclusive: only one transition can be running on the element at the same time. Starting a new transition on the element stops any transition that is already running."
I have a shape that has hoverIn() and hoverOut() function and it can be dragged at the same time. My problem is when I drag too fast (not like really really fast), the mouse pointer may go outside of the shape boundary before the shape is actually moved. This cause hoverOut to be fired and it messes up with my dragging function. When I drag slow, this doesn't happened since the shape displacement is small and the mouse is always inside.
How can I handle the fact that if I'm dragging I don't want to deal with hoverOut. I tried the unHoverfunction(), it partially worked but now after dragging and leaving the shape the hoverOut function is not fired as it should be.
I've just created a flag, it seems like no built-in solution exist. Thanks for your time.
I am having problems detecting mouseover events on SVG path elements. It seems that the smaller the strokeWidth for the path element, the less success I have in detecting the mouseover.
Also, I am using jquery-svg plugin to do the drawing.
Below is a fiddle of trying to detect using a jquery mouseover event on the path element.
Mouseover Fiddle
Below is a fiddle of trying to detect by attaching a mousemove listener to svg, then using document.getElementFromPoint.
getElementFromPoint Fiddle
Neither of these seem to work reliably, especially if the mouse is moving fast. Is it possible to make either of these more sensitivity to better detect the mouseover? Or perhaps a better way of doing this?
The way browsers work, you don't get mouseover events continuously, but you get one each time the operating system updates the cursor position. And if the mouse is moving fast, you will get a events a few pixels apart. The mouse doesn't slide over the document, it jumps. Here's a jsfiddle showing where each event occurs. There's nothing that you can do to get mouseover events for all the elements between two consecutive positions of the cursor.
You could do something different: remember the previous location of the mousemove event, compute the line between that point and the current mouse position, and compute all the intersections between this line and all the other shapes in the document. But that is going to be resource-intensive, since there's no API available for that, you'll have to compute intersections yourself. There is a library that can help you.
For a 'shooting gallery'-like game, there are images with an onMouseOver event that will show a crosshair (which follows the mouse) and an onMouseOut event that will hide it.
However, the instant the crosshair becomes visible, it covers the below image, activating its onMouseOut event which hides the crosshair.
This creates a 'flicker' effect which is very, very ugly.
Is there a way to prevent the crosshair image from obscuring the target below?
One easy solution is to create an onMouseOver for the crosshair that shows it (I know this is redundant, but it works for menus and the like).
Another solution would be to set a timeout in the onMouseOut to hide the crosshair. It will reduce the flickering and the crosshair will be visible out of the target for a short time.
Edit:
And another would be to perform a collision detection between the mouse and the elements, changing the mouseOver to a mouseMove in the target's parent element:
http://jsfiddle.net/sHecT/1/
The code is quite long, but its logic is what I've said above.
Just a note: The getElementsByClassName doesn't work in older browsers, but you can use an array of targets, as you create them, add them to an aray (probably you already has one) and use it in place of this call;
This one illustrates an easing function to position the crosshair smothly and the cursor is hidden when over the target
http://jsfiddle.net/sHecT/2/
Instead of using an image for your background, and an image for your cross-hairs, what if you used a div with a background image for your background instead, and then made the cross-hairs image a child of that div?
I haven't tested this, but since the cross-hair image would now be part of the content of the background div, I would imagine that it would no longer trigger a mouseout.
I believe The pointer-events property is exactly what you're looking for. It basically prevents an element from being the target of any sort of mouse-event so the elements underneath it can handle them instead. Parent elements can still react to the event.
HOWEVER it is only supported in the later versions of Firefox, Safari, and Chrome, and it probably won't be in the CSS specification until CSS4. It an awesome solution for supported browsers, but if you want to fix the issue in any version of IE or Opera you'll also need an alternate solution. I felt like it deserved a mention here though. :D