Alec Sanger Alec Sanger - 3 months ago 20
Javascript Question

Raphael and IE. Mouseout workaround

I've run into an issue using Raphael for SVG effects on an IE browser. When I mouseover an object, the animation occurs as expected. On mouseout, however, the mouseout action is never called, so the object(s) are stuck in their mouseover state.

I've seen others complain about this issue in the past, but the only solution I saw was to force the mouseover event on every object to return everything != current object to their normal state. I'd rather not do a general "reset everything" because I have quite a few objects, so I'm wondering if anyone has an alternative they can suggest. I was thinking about storing the last object with the last triggered mouseover in a variable and only resetting that on every mouseover, which could work....

Answer

Since Raphael 2.0.2, there's been an issue in Raphael and Internet Explorer (all versions) where various manipulations of a path such as resetting a transform, .toFront(), or .toBack() called from hover() while hovering can cause hover ins to loop endlessly and/or hover outs to be missed.

While hover mostly works fine in IE for mouseout, there are a few things I've found that that can trip it up, causing it to a) ignore mouseouts as you describe and b) trigger the mouseover event recursively such that if you put a console.log in there, IE developer tools' console breaks and turns grey... which sometimes seems to also stop it recognising mouseouts.

Here are the things I've encountered which cause this:

  • Resetting a transform, which would cause the element to move from under the mouse, then reapplying it putting the element back under the cursor. non-IE carries on like nothing happened and works fine, IE freaks out as described above.
  • .toFront() and .toBack() - non-IE recognises the moved element as being the same element in the same X Y position, IE freaks out as described above.

There are some observations and demonstrations in this jsfiddle (read & uncomment the various comments).

A good workaround here, is to have some kind of flag like for example 'path.data( 'hoverIn', true );on mouse in and 'path.data( 'hoverIn', false ); on mouse out, then wrap any .toFront() or offending transforms in a check that !path.data( 'hoverIn' ) so that it can only happen once until the mouse out happens. Or, store a reference to the most recently hovered path somewhere after the toFront() or whatever, then don't toFront() or whatever if this path is also the most recently hovered one.

Comments