1

This is a follow-up related to brainjam's solution to finding the pointer position relative to an element.

For reference, here's his solution:

function mouseMoveHandler(e)
{
    var style = getComputedStyle(c,null) ;
    var borderTop = style.getPropertyValue("border-top-width") ;
    var borderLeft = style.getPropertyValue("border-left-width") ;
    var paddingTop = style.getPropertyValue("padding-top") ;
    var paddingLeft = style.getPropertyValue("padding-left") ;
    var offsetX = e.offsetX || e.layerX || 0 ;
    var offsetY = e.offsetY || e.layerY || 0; 
    var x = offsetX ;
    var y = offsetY ;
    if(window.navigator.userAgent.indexOf("Opera") === -1){ 
        x -= parseInt(paddingLeft,10) ;
        y -= parseInt(paddingTop,10) ;
        if(window.navigator.userAgent.indexOf("MSIE") === -1){
            x -= parseInt(borderLeft,10)  ;
            y -= parseInt(borderTop,10)  ;    
        }
    }
    // do something with x, y
}

Now I have a few concerns with this code:

  1. This code uses offsetX/offsetY. As far as I can tell, the DOM level 2 events specifications specify the only the attributes clientX/clientY and screenX/screenY for MouseEvent. As far as I can tell, the DOM level 3 draft events specifications only specify the same two attributes for MouseEvent. Is offsetX/offsetY technically "non-standard", or am I missing something here? Is it safe to assume it's going to stick around?

  2. I had some document like such:

Where I can move the rect around the scene by modifying the transform of viewport.

How I'm updating the viewport's transform:

// matrix is the updated transformation of the viewport
var transform = svg_base.createSVGTransformFromMatrix(matrix);
viewport.transform.baseVal.initialize(transform);

In Chrome and Firefox, this works perfectly fine. However, in IE10 and Opera 12, there's some kind of issue where the offset value keeps "jumping around". Note that as far as I can tell, this only happens when this transformation update process is involved. Commenting it out and it seems like the offsetX/offsetY values are well behaved.

Here's a short log of the offsetx/offsetY value from IE10 if I select the bottom left corner and drag it up:

 64, 128 
 65, 127 
 66, 128 
 67, 125 
 64, 127 
 67, 122 
 64, 127 
 67, 119 
 64, 128 
 67, 118 
 64, 126 
 67, 115 
 64, 126 
 67, 112 
 64, 126 
 67, 109 
 64, 126 
 67, 106 

Notice how the coordinate jumps around as I move the mouse steadily up (and very slightly to the right, though this wasn't intentional). This results in a flickering effect, and eventually the viewport will get out of sync with the intended move operation. My question is why does this happen in IE10/Opera and not Firefox/Chrome? Is there a better way to get the mouse pointer's location relative to the svg_base element? Or is there a better method for updating the viewport transformation matrix?

Community
  • 1
  • 1
helloworld922
  • 10,801
  • 5
  • 48
  • 85

1 Answers1

2

After some testing with FireFox, Chrome, IE10, and Opera (most used modern desktop browsers, minus Safari due to inaccessibility) I developed an alternative based off of quirksmode.org's solution.

I'm not actually sure how robust this is under all situations, or how it will perform with older browsers. As far as I know, the vast majority of the code is "standard compliant", with a one exception the use of pageX/pageY for old browser support (not sure which ones this applies to, this is part of quirksmode.org's implementation).

// params:
//  - elem: the element to get pointer coords relative to
//  - e: MouseEvent object
function mousePosRelElement(elem, e)
{
    var x = 0;
    var y = 0;

    var bounds = elem.getBoundingClientRect();

    // not actually sure which browsers use pageX/pageY, just left in from quirksmode implementation
    if(e.pageX !== undefined && e.pageY !== undefined)
    {
        x = e.pageX - bounds.left - document.body.scrollLeft - document.documentElement.scrollLeft;
        y = e.pageY - bounds.top - document.body.scrollTop - document.documentElement.scrollTop;
    }
    else if(e.clientX !== undefined && e.clientY !== undefined)
    {
        x = e.clientX - bounds.left;
        y = e.clientY - bounds.top;
    }

    return {x: x, y: y};
}

comments and suggestions are welcome and encouraged.

helloworld922
  • 10,801
  • 5
  • 48
  • 85
  • Why do you use pageX/Y at all instead of just clientX/Y? – Ali Shakiba May 01 '15 at 04:42
  • As stated, I'm essentially copying the implementation on quirksmode.org. I have no idea why it's there, and I didn't have the time to actually test this on multiple versions of each major browser to see if the code ever gets executed. – helloworld922 May 01 '15 at 18:36
  • I check it out, read the reference article (link is broken, found it elsewhere), checked browser usages by version: clientX/Y works correctly in more than 99% of browsers, it only is implemented incorrectly in some old minor browsers. But regarding pageX/Y, additional values are there to calculate correct clientX/Y using pageX/Y, but I think you only need either body's scroll or docElem's scroll, see [here](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX). – Ali Shakiba May 01 '15 at 22:14