Duplicate events in prototype - javascript

I have a setup where I have a grid of elements and when I rollover each element a popup appears like an advanced tooltip. I first check if the popup needs to follow the moused over elements mouse position, if so I use a mousemove event. I first stopObserving in case there was one set before, then I start observing. Do I really need to do this or is prototype smart enough to not to add duplicate events on the same element.
show:function(param){
if(this.isFollow){
$(param.target).stopObserving('mousemove', this.onMouseMove);
$(param.target).observe('mousemove', this.onMouseMove);
}
},
//param.target is the element that is being rolled over. I pass this in to my show method to then find its x and y position.
onMouseMove:function(event){
var xPos = Event.pointerX(event);
var yPos = Event.pointerY(event);
_self._popup.setStyle({left: xPos + 10 + "px", top:yPos + 10 + "px"});
}
Second question. When I move my mouse across the elements really fast my popup that is following the mouse sometimes lags and the mouse goes over the popup obstructing the mouseover event on the element below it.
I presume this is the nature of the mousemove as its not rendering fast enough. Should I be using setTimeout or something like that instead of mousemove, to prevent this lag.

1) No, Prototype won't set the same event handler twice. It'll only happen if you declare your handler function in-line (i.e. element.observe('click', function(){…})) since the handler will be sent a newly created function each time, and never the exact same instance of a function.
But in your case, where you're referring to the onMouseMove function, Prototype will check whether that particular function is already registered for that particular event, on that particular element. And if it is, it won't be registered again.
2) You can't avoid the lag on fast mouse movements, no. The browser won't send the mousemove events fast enough. You could use a timer, but I'd probably try registering a single mousemove handler for the parent element of all the grid-elements (or maybe even document itself), and use the X/Y coordinates to figure out which grid-element to show the tooltip for. Then you don't have to bother with setting event handlers for each element. I.e. if the grid was a standard table, I'd listen for events on the <table> element itself, rather than on each and every <td>. Especially if you still want to implement a timer, I should think, it'd be easier to deal with everything in one place (otherwise, a timer might accidentally execute on some element you've already moused out of, and your tooltip will flicker back and forth or something. If you only want 1 tooltip at a time, it's easier to manage it in 1 place.)

Related

Javascript override user mouse event

I have a bit of javascript that will allow the user to move stuff around using the mouse, so the user can click and drag things around, which is working all fine, but what I am struggling with is being able to override the users click event.
So what I am trying to do is, if the user moves the item to a certain position I want to stop the click and hold event, this would mean the user would have to the go an reselect the item again and click and drag again.
Can you override the users mouse action from javascript? It seems simple but I am unable to find a way in my javascript to stop the mousehold event
You can try to override onmousedown to store the mouse coordinates and fire the "real click" event on onmouseup if the mouse position did not changed (or if the change is less than say 5 pixels).
document.getElementById('myElement').addEventListener('click', function(e) {
e.preventDefault(); // here is your override
doSomethingElse(); // or not
});
Same thing for IE but use attachEvent instead of addEventListener
Perhaps instead of blocking events, you can put some logic inside your onclick handler to check for this condition?
For example, maybe a couple of properties to maintain state. You could call one itemSelected, which must be true in order for the the item to move. Then if you set itemSelected to false, another click will be necessary to toggle it again.

Triggering mousemove on the mouse's current position

Suppose we have a <div> with a mousemove handler bound to it. If the mouse pointer enters and moves around this div, the event is triggered.
However, I am dealing with a rich web application where <div>s move around the screen, appear and disappear... So it may happen that a <div> appears under the mouse pointer. In this case, mousemove is not triggered. However, I need it to be. (Note that replacing mousemove with mouseover does not change this behavior.)
Specifically, the <div> has to be highlighted and I deem it as a UI flaw to require the user to do a slight mouse move in order to trigger the highlighting.
Is it possible to trigger the mousemove event programatically? And I do not mean
document.getElementById('mydiv').onmousemove();
because onmousemove is parametrised by the event object, which I do not have.
Is it possible to make browser behave as if onmousemove was triggered on the current mouse's position (although in fact the mouse didn't move)?
You could modify your mousemove to keep a state variable with the current mouse coordinates, and use that information to perform a collision detection that you call both on mouse move, and on moving a div.
A little example of what that might look like
You actually can create a mousemove event object to pass in, using something like this:
window.onload = function () {
document.getElementById("test").onmousemove = function(e) { console.log(e); };
document.getElementById("test").onclick = function(e) {
var e = document.createEvent('MouseEvents');
e.initMouseEvent('mousemove',true,true,document.defaultView,<detail>,<screenX>,<screenY>,<mouseX>,<mouseY>,false,false,false,false,<button>,null);
this.onmousemove(e);
};
};
Of course, here I'm firing it on a click, but you can do it on whatever event you want, such as when your div becomes visible, check to see if the mouse is within it. You just need to make sure your parameters are right, and you need to track the mouse position on your own. Also, there's some differences in IE, I think. Here's my source: http://chamnapchhorn.blogspot.com/2008/06/artificial-mouse-events-in-javascript.html. He added a little extra code to account for it.
Here's a fiddle to play around with. http://jsfiddle.net/grimertop90/LxT7V/1/

How does the triggering of mousemove work in Javascript?

I have an object that prints the mouse's x and y positions on every mousemove.
It's something like this:
$('#canvas').mousemove(function(e){
$('#output').prepend(e.pageX + ',' + e.pageY);
});
I've noticed that when you move over the object really fast it only prints out a few positions.
I'm not exactly unhappy that it does that (because it would be quite exhaustive to have it do something for all the hundreds of pixels you've crossed) but I am wondering how this works.
Is the mousemove event limited to a certain amount of triggers per second or what?
(Btw: this was tested on Chromium in Ubuntu Linux)
"Mice only report their position to the operating system n times per second, and I think n is usually less than 100"
You may want to look at this, as this may be browser dependent,
http://javascript.info/tutorial/mouse-events#mousemove-and-mouseover-frequency, but, if you look at this question, there is a suggestion on how to get better response.
How to set mousemove update speed?
i think it's synchronous. It's doesn't get triggered for every pixel in which you move your mouse, which means that the events are not queued up .
Say if you have some some code like this.
$('#canvas').mousemove(function(e){
//Some code which takes seconds to execute
//All subsequent events won't be dispatched while this event handler is executing.
});
Say if you move mouse while the mouse move event handlers execute. The mousemove handler won't be triggered.
Here is a example for handler which will take seconds to execute. --> http://jsfiddle.net/78Hf3/1/
And one that take only few time --> http://jsfiddle.net/78Hf3/2/

Detect if mouse is over an element when page loads with Javascript

I have an image that I want to have trigger certain behaviors when the mouse is over, I have a mouseover and mouseout method, but if you happen to have your mouse over the image when the page loads, the mouseover method never fires until you leave the image and come back over it.
Is there a way to detect if the mouse is over an element on the fly without the mouse having to be off of the element and then come over the element to trigger the JS mouseover event? Like is there a document.getElementById("blah").mouseIsOver() type function in Javascript?
I believe this is possible without any action from the user. When your page loads, bind the mouseover event to your image and hide your image (i.e. using CSS display:none). Use setTimeout() to show it again in a few milliseconds (10 should be enough). The even should be fired.
If you don't want to cause the 'flick' effect on your image, you may try using some temporary element instead, attaching event to it, and delegating the event onto your image.
I have no idea if this is cross-browser solution, but it worked from my Firefox 3.0 console ;)
You could use the mousemove event. That would trigger anytime the user moves a mouse; so the only instance of the trigger not firing would be if the user does not move the mouse at all, which should be rare.
The only problem with this is that the event would fire anytime the mouse would move over your image, so you would get a LOT of those events while over the component. What you would probably need to do is implement some sort of flag within your method when the event fires. You turn on the flag when the event first fires, and you turn it off when you leave the component.
This is less than ideal, but I think this will probably satisfy your problem scenario. The following is some quick pseudo code on what that solution might look like, I think it should work.
<img src="blah.png" onmousemove="JavaScript:triggerOn(event)" onmouseout="JavaScript:triggerOff(event)"/>
...
<script type='text/javascript'>
var TriggerActive = false;
function triggerOn(e){
e = e||window.e;
if( !TriggerActive){
TriggerActive = true;
// Do something
} else {
// Trigger already fired, ignore this event.
}
}
function triggerOff(e){
e = e||window.e;
if(TriggerActive)
TriggerActive = false;
}
</script>
You can find some great mouse event information including browser compatibility notes here.
Use document.querySelectpor and onload/onready events.
var a = document.querySelector('#a:hover');
if (a) {
// Mouse cursor is above a
}
else {
// Mouse cursor is outside a
}
There is no way to get the mouse coordinates aside from listening for mouse events, namely mousemove, mouseover etc. However, these events are very sensitive in the sense that moving the cursor by just one pixel is enough to trigger them, so having the cursor hover over your image while perfectly still should be somewhat unusual.

Javascript: Is it possible to get hold of the mouse position outside of an event handler?

I want to get hold of the mouse position in a timeout callback.
As far as I can tell, this can't be done directly. One work around might be to set an onmousemove event on document.body and to save this position, fetching later. This would be rather expensive however, and isn't the cleanest of approaches.
I think you'll have to do the same thing as #Oli, but then if you're using jQuery, it would be much more easier.
http://docs.jquery.com/Tutorials:Mouse_Position
<script type="text/javascript">
jQuery(document).ready(function(){
$().mousemove(function(e){
$('#status').html(e.pageX +', '+ e.pageY);
});
})
</script>
The direct answer is no but as you correctly say, you can attach events to everything and poll accordingly. It would be expensive to do serious programming on every onmousemove instance so you might find it better to create several zones around the page and poll for a onmouseover event.
Another alternative would be to (and I'm not sure if this works at all) set a recurring timeout to:
Add a onmousemove handler to body
Move the entire page (eg change the body's margin-top)
when the onmousemove handler triggers, get the position and remove the handler. You might need a timeout on this event too (for when the mouse is out of the viewport)
Uberhack but it might work.
As you described, the most straightforward way to do it is setting the onmousemove event handler on the body. It's less expensive than you think: very little computation is done to store the coordinates, and the event gets fired 50 to 100 times a second when the mouse moves. And I suspect a typical user won't move their mouse constantly when viewing a web page.
The following script helps with counting event handlers; on my machine, moving the mouse around in Firefox, this added 5% to 10% to my CPU usage.
<script type="text/javascript">
jQuery(document).ready(function(){
var count = 0;
$().mousemove(function(e){ count += 1; });
$().click(function(e){ $('#status').html(count); });
});
</script>

Categories

Resources