briancherne / jquery-hoverIntent

hoverIntent jQuery Plug-in

Home Page:https://briancherne.github.io/jquery-hoverIntent/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

return current pageX, pageY with the event

usmonster opened this issue · comments

It could be generally useful if the event passed to the handlers could also hold the current X & Y coordinates of the mouse at the time of firing. This could be added as part of the event.data, or more seamlessly (though potentially an unwanted side-effect for some) copied over the pageX/pageY of the returned event itself. This would make it much easier for those who want their handler to, for example, position something relative to the location of the pointer at the time of firing.

Thoughts? If I have time and there's interest, I can put an example implementation in a pull request.

You're saying this doesn't work from the handlerIn and handlerOut? http://api.jquery.com/event.pageX/

Correct, @roydukkey. handlerIn and handlerOut get passed the same original event that was triggered at mouseenter/mouseleave time, whose unmodified pageX and pageY will be that of the pointer when it first entered the target. This makes it a bit more inconvenient for one who wants to, for example, implement a tooltip effect that shows up next to the mouse pointer.

Here's an example of the behavior, which is most visible when the target element has a large area:
http://jsfiddle.net/RGULk/6/

You'll notice that the tooltip is positioned based on the pointer position at the last interval check, not at its position then the handler is actually fired. This is not good for UX.

Whoops! Wrong linked issue. (Meant # 12.) Ignore above commit reference.

+1 for this issue. Worked around this temporary by passing cX and cY on the apply:

69.   return cfg.over.apply(ob,[ev, {x:cX, y:cY}]);

@flesler, your workaround is one of a few ways to do it, though I think the most appropriate solution would keep the interface as close to normal "hover" as possible, i.e. just return an event by itself. It would be easy to implement: just before the handler is triggered, simply copy the X/Y values of the last mousemove event over the X/Y properties of the original mouseenter event that would be subsequently passed to said handler.

The real issue, however, is that this would be a change that could break the way some folks might be using the plugin today. They might rely on the current behavior, even though it is counterintuitive, IMO -- if you really want something as similar as possible to normal hover behavior, you arguably want the coordinates on the passed event to match the actual position of the mouse pointer at handler-time.

I'm more than willing to put in a pull request to add this behavior (including nice bold text in the changelog :) if @briancherne is in agreement with my copy-coordinates approach. Perhaps it can be an option, but I think it's more correct and in line with the spirit of the plugin to have this become the default behavior.

I'm aware that this is not a good final solution. Tried copying the values to the event (pageX,pageY) and that breaks the behavior, after an over, more are triggered once you move.

@briancherne :bump:

Any thoughts on the above discussion?

Also, @flesler, can you please elaborate on how/when copying the *X/*Y values to the passed event breaks behavior? I'm not sure I understand. Perhaps provide a reference implementation and/or jsfiddle?

@usmonster - I'm in agreement with the copy-coordinates approach, as the default (and only) behavior. Just make sure to increment the version and note the (possible) backwards incompatibility for folks that were using the pageX/pageY of the original event. If someone complains we can consider adding a configuration option.

commented

While implementing this I realize the possibility that the most common use case may care about the current pointer coordinates only for the over handler and not for out. That said, I'm hesitating--should I still copy the current values onto both events (for consistency), or is it better to copy them only for the over handler?

Copying current coordinates to the event passed to out would still allow access to the originalEvent's coordinates, though this could arguably be a more surprising/less intuitive default behavior..

Anyone have a compelling use case to support either option?

commented

I keep going back and forth on consistency vs. intuition issue, and it's blocking the release...

Basically, I'd just like some/any feedback as to whether it makes more sense to leave the out handler event as-is (it has the pointer coordinates of the original mouseleave event), or if it's objectively better to mirror the new over behavior by giving it the coordinates that are "current" at the moment when the handler is called (i.e. after the timeout, if any is given). Note that the latter behavior would require additional mousemove tracking between the mouseleave and said timeout, though the major benefit would be to make both current and mouseleave-time coordinates (via event.originalEvent) available to the out handler.

Thoughts? @flesler, @roydukkey, @briancherne?

commented

In my opinion it makes sense to leave it the way it currently is, because out means, well when the mouse moves out. So my vote is to leave e.pageX and e.pageY alone.

It would be easy to add e.delayedPageX and e.delayedPageY. But, I'm not in favour of modifying the behaviour of jQuery.

Wouldn't it be fine to update the out signature to include a parameter for things that are additional to jQuery? Something along these lines:

// out: Function( Event eventObject, Object delayedCoord )

$( "p" ).hoverIntent( function() { }, function( event, delayed ) {
     delayed.pageX;
     delayed.pageY;
});
commented

Thanks for the rapid feedback, @roydukkey! I agree with the semantics of out, though the same reasoning could be applied to the over case. One can imagine valid use cases where someone might want to have access to the actual handler-time coordinates instead of (or in addition to) the event-time coordinates for both mouseenter/"over" and mouseleave/"out" cases. Applying the same kind of modification for both event/handler pairs would also preserve a kind of semantic and behavioral symmetry.

All that said, I may be leaning slightly toward leaving the mouseleave/out case alone, at least for this release, since the necessity of the change is currently less compelling than for the mouseenter/over case. Still, I'll leave the issue open a bit for other feedback until a decision is made.

As for the proposed alternatives, I doubt we'd add a delayedPageX value to the event or change the API of the handler in any case, especially since the latter could arguably be a more disruptive change. thanks for the suggestions, though!

commented

Right. I did overlook the over case, but do you mind elaborating on how you feel the latter could be disruptive? Though the handler would be applied as Function( Event eventObject, Object delayedCoord ) both parameters are still optional and do not present any new requirements in implementing hoverIntent. out: function() { } and out: function( event ) { } would still be acceptable without any issue.

commented

No problem! To elaborate, the disruption I was talking about is more to the users of the plugin, since hoverIntent is meant to be a drop-in replacement for .hover. If hoverIntent passed its own proprietary object to the handler--which can be any user-provided function--we have no guarantee that the function would behave the same. What if someone reuses the out function elsewhere and it already has different behavior based on its arguments? This would break for them. I think most behavior changes like this should be done in a way that doesn't change the API/contract that says "we will only pass an Event to the callback, even if your callback can take more arguments." Hope that makes sense.