Need help understanding pageX, clientX, and scrollLeft in a JavaScript function that makes an image draggable

The html document below contains JavaScript code that makes the image in the document draggable. I understand all the code except for the function fixPageXY(e). Can someone please explain the syntax of fixPageXY(e)  and why it's needed? The program actually works without it if you comment it out.  The syntax I find especially confusing is this:

  e.pageX = e.clientX + (html.scrollLeft || body && body.scrollLeft || 0)

What exactly is being added to e.clientX here? It looks like there are three Boolean conditional statements in the parenthesis.

 
<!DOCTYPE HTML>
<html>
<head> 
<body>

<img src="http://javascript.info/files/tutorial/browser/events/ball.gif" id="ball"/> 

<script>
document.getElementById('ball').onmousedown = function() {
  this.style.position = 'absolute';  
  var self = this
 
  document.onmousemove = function(e) { 
    fixPageXY(e);   
    self.style.left = e.pageX-25+'px'
    self.style.top = e.pageY-25+'px'
  }
  this.onmouseup = function() {
    document.onmousemove = null
  }
}

function fixPageXY(e) {
  if (e.pageX == null && e.clientX != null ) {
    var html = document.documentElement
    var body = document.body
 
    e.pageX = e.clientX + (html.scrollLeft || body && body.scrollLeft || 0)
    e.pageX -= html.clientLeft || 0
     
    e.pageY = e.clientY + (html.scrollTop || body && body.scrollTop || 0)
    e.pageY -= html.clientTop || 0
  }
} 

document.getElementById('ball').ondragstart = function() { return false }
</script>
</body>
</html>

Open in new window

ArchimelAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ArchimelAuthor Commented:
I'm also very confused about this if condition:

 if (e.pageX == null && e.clientX != null )
0
Ugo MenaCommented:
It would seem that the fixPageXY function is capturing the X and Y positions when the user (client) drags the object beyond the window size. In which case the body && body.scrollLeft would be the beyond page X position

same thing for the Y position that may go beyond the window size.

Comment this out and try to drag the object beyond the window size and it will not detect the X or Y positions.
0
Robert SchuttSoftware EngineerCommented:
On the page I linked to on your previous question, this 'fix' function is presented under the header "IE<9 workaround".

The mousemove code uses e.pageX and Y which are not available in IE8 for example. So the fix function uses object detection to determine if the code is running in a browser that offers those mouse event properties and if not, adds them with a value that is based on other event properties, specifically adding up the scroll position of the body and the client position which is the position relative to the top left corner of the view-port.

The "||" notation is being used as a shortcut expression to provide a fallback for non-existing properties. So "html.scrollLeft || body && body.scrollLeft || 0" means: if html.scrollLeft exists then use that, otherwise if body and body.scrollLeft exist then use the latter. Otherwise use 0.

And then the result of all that (which should hold the amount of pixels the body is scrolled to the right regardless of the browser used) is added to e.clientX to calculate the 'pageX' coordinate and that is stored in the event object (as it would be automatically already in newer browsers).

If you have no need to support old browsers and the positioning looks good to you without the fix, then just take it out.

If you do want to support old browsers, fair warning: I tested in IE8 and it didn't work. Apart from that, some of the code is not really correct. With some small additions you can get it to work but maybe we shouldn't be worrying about IE8 too much anymore.

I did find out by the way that I couldn't get it to work earlier because for some reason this code doesn't work in jsFiddle, I have put a demo on my website now, also to show how to add code again to capture the distance and drag more naturally, leaving the mouse pointer where it was in relation to the image at the moment of first click.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

ArchimelAuthor Commented:
So it's possible in some old browsers for images not be visible because they're positioned too far to the left, causing them to go off the screen? The reason is that old browsers can only measure mouse position relative to the whole screen, but new browsers can measure mouse position relative to either the whole screen or browser window?

 if (e.pageX == null && e.clientX != null )
If this statement is true, it means you have an old browser (< IE9)?
Old browsers have a clientX only, and clientX means the entire screen?
New browsers have both clientX and pageX, and clientX means the browser window while pageX means the entire screen?

 var html = document.documentElement  //this represents the whole screen?
 var body = document.body //this represents the browser window?
0
Robert SchuttSoftware EngineerCommented:
No, that would only happen if you weren't careful in your programming and use the wrong variables to calculate the position while dragging. This fix only seems to concern IE8 and older although I have seen a similar fix for FireFox some years ago. It mostly has to do with specifications not being followed in earlier browsers but sometimes also specifications being changed. Again: it's important to ask yourself if you really need to support older browsers.

Have a look at the picture below the code on this page, it shows why you need to look at body scroll position. So it would go wrong if your page is wider than the screen, scroll right a bit, then use clientX instead of pageX and you would see that the image is not being positioned correctly.

If this statement is true, it means you have an old browser (< IE9)?
It's a bit general but it seems to hold true in my (limited) test of it. Remember, lots of these tests exist for different purposes. It's important to note that object detection should be used not globally but for each specific action/property you need. Exactly because that was getting out of hand, lots of people are now using libraries like jQuery which do more but for starters make an end to most 'manual' cross browser scripting.

//this represents the browser window?
No, both represent the page (which can be larger than the window) but that part of the code is more about different properties those different html elements can hold in various browsers. They just want to get the scroll offset from any place they can get it.
0
ArchimelAuthor Commented:
Thank you again. I don't think it's important to support very old browsers, but I'm glad I understand the code better. I may need this knowledge to resolve cross-browser compatibility issues later.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.