Detect mousemove when over an iframe?

49,232

Solution 1

If your target isn't Opera 9 or lower and IE 9 or lower you can use css attribute pointer-events: none.

I found it the best way just to ignore iframe. I add class with this attribute to iframe in onMouseDown event and remove in onMouseUp event.

Works perfect for me.

Solution 2

Iframes capture mouse events, but you can transfer the events to the parent scope if the cross-domain policy is satisfied. Here's how:

// This example assumes execution from the parent of the the iframe

function bubbleIframeMouseMove(iframe){
    // Save any previous onmousemove handler
    var existingOnMouseMove = iframe.contentWindow.onmousemove;

    // Attach a new onmousemove listener
    iframe.contentWindow.onmousemove = function(e){
        // Fire any existing onmousemove listener 
        if(existingOnMouseMove) existingOnMouseMove(e);

        // Create a new event for the this window
        var evt = document.createEvent("MouseEvents");

        // We'll need this to offset the mouse move appropriately
        var boundingClientRect = iframe.getBoundingClientRect();

        // Initialize the event, copying exiting event values
        // for the most part
        evt.initMouseEvent( 
            "mousemove", 
            true, // bubbles
            false, // not cancelable 
            window,
            e.detail,
            e.screenX,
            e.screenY, 
            e.clientX + boundingClientRect.left, 
            e.clientY + boundingClientRect.top, 
            e.ctrlKey, 
            e.altKey,
            e.shiftKey, 
            e.metaKey,
            e.button, 
            null // no related element
        );

        // Dispatch the mousemove event on the iframe element
        iframe.dispatchEvent(evt);
    };
}

// Get the iframe element we want to track mouse movements on
var myIframe = document.getElementById("myIframe");

// Run it through the function to setup bubbling
bubbleIframeMouseMove(myIframe);

You can now listen for mousemove on the iframe element or any of its parent elements -- the event will bubble up as you would expect.

This is compatible with modern browsers. If you need it to work with IE8 and below, you'll need to use the IE-specific replacements of createEvent, initMouseEvent, and dispatchEvent.

Solution 3

Another way to solve this that work well for me is to disable mouse move events on the iframe(s) with something like on the mouse down:

$('iframe').css('pointer-events', 'none');

and then, re-enable mouse move events on the iframe(s) on the mouse up:

$('iframe').css('pointer-events', 'auto');

I tried some of the other approaches above and they work, but this seems to be the simplest approach.

Credit to: https://www.gyrocode.com/articles/how-to-detect-mousemove-event-over-iframe-element/

Solution 4

MouseEvent.initMouseEvent() is now deprecated, so @Ozan's answer is a bit dated. As an alternative to what's provided in his answer, I'm now doing it like this:

var bubbleIframeMouseMove = function( iframe ){

    iframe.contentWindow.addEventListener('mousemove', function( event ) {
        var boundingClientRect = iframe.getBoundingClientRect();

        var evt = new CustomEvent( 'mousemove', {bubbles: true, cancelable: false})
        evt.clientX = event.clientX + boundingClientRect.left;
        evt.clientY = event.clientY + boundingClientRect.top;

        iframe.dispatchEvent( evt );

    });

};

Where I'm setting clientX & clientY you'll want to pass any info from the content window's event to the event we'll be dispatching (i.e., if you need to pass something like screenX/screenY, do it there).

Solution 5

The page inside your iframe is a complete document. It will consume all events and have no immediate connection to it's parent document.

You will need to catch the mouse events from javascript inside the child document and then pass this somehow to the parent.

Share:
49,232
Charles Zink
Author by

Charles Zink

Updated on January 19, 2021

Comments

  • Charles Zink
    Charles Zink over 3 years

    I have an iframe that takes up the entire window (100% wide, 100% high), and I need the main window to be able to detect when the mouse has been moved.

    Already tried an onMouseMove attribute on the iframe and it obviously didn't work. Also tried wrapping the iframe in a div like so:

    <div onmousemove="alert('justfortesting');"><iframe src="foo.bar"></iframe></div>
    

    .. and it didn't work. Any suggestions?

  • Rehno Lindeque
    Rehno Lindeque over 12 years
    Any ideas how to pass up the mouse coordinates properly?
  • JeremiahLee
    JeremiahLee over 11 years
    This is a great, and I believe best, solution. Only current drawback is that IE does not yet support the pointer-event attribute. caniuse.com/#search=pointer-events
  • jeremy
    jeremy almost 8 years
    See my newest answer for more info regarding deprecation & how to deal w/ it
  • Lukus
    Lukus over 7 years
    Borrowed from your idea. This is a great answer since you do not have to worry about bubbling events up to the parent from child
  • Ethan
    Ethan over 6 years
    Is there any way for this to work but for the iframe to still be interactive?
  • HastingsDirect
    HastingsDirect about 6 years
    Only problem with this is you can't interact with the iframe in any way with pointer events set to none, so for a lot of use cases this won't work
  • Johan Danforth
    Johan Danforth almost 6 years
    Very simple solution that worked for me. Worth trying.
  • mathheadinclouds
    mathheadinclouds over 4 years
    a good start, but incomplete. Not all relevant data is copied from the event captured on the iframe to the generated clone. One thing missing is evt.buttons. Looking at how many keys a MouseEvent has, I'm almost certain that this is not the only thing missing. By running this solution side by side with Jagi's solution, one should be able to 'fill in the gaps' step by step.
  • mathheadinclouds
    mathheadinclouds over 4 years
    maybe loop through all keys using Object.keys, and do standard cloning, and then do by hand only those keys where something changes, such as .clientX, .clientY as in the solution.
  • mathheadinclouds
    mathheadinclouds over 4 years
    I'm using this solution with one line added, namely evt.buttons = event.buttons, and it's working for what I'm doing. For other use cases, you probably have to copy more, as I said.
  • mathheadinclouds
    mathheadinclouds over 4 years
    IE doesn't have CustomEvent, but there's a polyfill, see developer.mozilla.org/en-US/docs/Web/API/CustomEvent/…
  • jeremy
    jeremy over 4 years
    @dieterh glad to hear it
  • svarlamov
    svarlamov about 4 years
    This worked perfectly for me. Also, I referenced a somewhat simplified strategy for the div overlay from this post
  • Tiago
    Tiago over 3 years
    Is this code right? Because I'm not getting data from the modal with iframe. Nothing happens, no error.
  • AryanJ-NYC
    AryanJ-NYC over 3 years
    Wow. I spent hours on this. To think it was THAT easy. Thanks so much!