JavaScript Coordinates

For moving elements around, it is necessary to learn about coordinates. The majority of JavaScript methods operate with one of the following two coordinate systems: Relative to the window and relative to the document. The first system is like position:fixed and is calculated from the window top/left edge. Its coordinates will be denoted as clientX/clientY.

The second one is similar to position:absolute and is calculated from the document top/left edge. They will be denoted as pageX/pageY.

These coordinates are equal to each other when the page is scrolled to the very beginning, in the way that the window top/left corner is the document top/left corner. Yet, when the document shifts, the elements’ window-relative coordinates change: they move across the window, and the document-relative coordinates stay the same way.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      #textId {
        height: 950px;
      }
      div {
        border: 1px solid red;
      }
      h1 {
        color: green;
      }
      h2 {
        color: blue;
      }
      body {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <div id="textId">
      <h1>Welcome to W3Docs</h1>
      <h2>MouseEvent clientX and clinetY Property</h2>
      <p>To get the x and y of the mouse pointer, click on this page.
      </p>
    </div>
    <p id="divId"></p>
    <p id="pageId"></p>
    <script>
      let elem = document.getElementById('divId');
      document.addEventListener('click', function(event) {
        elem.innerHTML = "clientX  " + event.clientX + ' : ' + " clinetY " + event.clientY;
      });
      let el = document.getElementById('pageId');
      document.addEventListener('click', function(event) {
        el.innerHTML = "pageX  " + event.pageX + ' : ' + " pageY " + event.pageY;
      });
    </script>
  </body>
</html>

So, for pageY the document-relative coordinate has remained the same, being counted from the top of the document. For clientY the window-relative coordinate has been modified making the arrow shorter. That is because the same point became nearer to the window top.

Element Coordinates: getBoundingClientRect

The elem.getBoundingClientRect() method returns window coordinates for a minimal rectangle enclosing elem like a DOMRect class object. DOMRect has two primary properties: x/y and width/height. The first propertyencompasses X/Y rectangle origin coordinates relative to the window. The second one includes the width and height of the rectangle. It can also be negative.

There are also additional derived properties such as top/bottom and left/right . The first one includes the Y-coordinate for the top/bottom edge of the rectangle. The second one- the X-coordinate for the left/right edge of the rectangle.

To see the window coordinates, click the button below:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      h1 {
        color: red;
      }
    </style>
  </head>
  <body>
    <div id="elem">
      <h1>Welcome to W3Docs</h1>
      <p>Move the mouse over the text</p>
      <div>
        Position:
        <p id='text'></p>
      </div>
    </div>
    <script>
      let elem = document.getElementById('elem');
      document.addEventListener('mousemove', function(event) {
        let rect = elem.getBoundingClientRect();
        document.getElementById('text').innerHTML = 'left: ' + rect.x + ', ' + 'top: ' + rect.y;
      });
    </script>
  </body>
</html>

While scrolling the page and repeating, it can be noticed that as the window-relative button position changes, its window coordinates are modified in parallel. The picture of elem.getBoundingClientRect() output will look as follows:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      #elem {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <div id="elem">Welcome to W3Docs</div>
    <script>
      let elem = document.getElementById('elem');
      alert("top: " + elem.getBoundingClientRect().top +
        " bottom: " + elem.getBoundingClientRect().bottom + 
        " right: " + elem.getBoundingClientRect().right + 
        " left: " + elem.getBoundingClientRect().left + 
        " width: " + elem.getBoundingClientRect().width + 
        " height: " + elem.getBoundingClientRect().height);
    </script>
  </body>
</html>

Please, take into account that decimal fractions can be used for coordinates. For example, 10.5. There is no necessity to round them while setting to style.left/top.

Also, negative coordinates can be used. For example, if you scroll the page in a way that elem is above the window, then elem.getBoundingClientRect().top will be negative.

There exist some similarities between the window-relative coordinates and CSS position:fixed. But there are differences, too. For example, in CSS positioning, the right property considers the distance from the edge, and the bottom- the distance from the bottom edge. In JavaScript, it is different: all the window coordinates are counted from the top-left corner.

ElementFromPoint(x, y)

At the window coordinates (x, y), the document.elementFromPoint(x, y) call returns the most nested element. Its syntax looks like this:

let elem = document.elementFromPoint(x, y);

For highlighting and outputting the element tag, which is in the middle of the window, the code below is used:

let centerX = document.documentElement.clientWidth / 2;
let centerY = document.documentElement.clientHeight / 2;
let el = document.elementFromPoint(centerX, centerY);
el.style.background = "green";
console.log(el.tagName);

As window coordinates are used by it, the element can be different depending on the current scroll position.

The document.elementFromPoint(x,y) method operates only when (x,y) are in the visible area.

In case any coordinate exceeds the window width/height or is negative, null is returned.

A typical error that may occur in case of not checking for it looks as follows:

let el = document.elementFromPoint(x, y);
// if the coordinates are outside the window, then el = null
el.style.background = ''; // Error!

“Fixed” Positioning

Mostly, coordinates are- used for positioning something.

The getBoundingClientRect method can be used for showing something next to an element. It is used for getting its coordinates, and then CSS getBoundingClientRect with right/bottom and left/top is used.

Let’s see an example with the usage of the createTextUnder(element, html) function:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the Document</title>
    <style>
      h1 {
        color: green;
      }
    </style>
  </head>
  <body>
    <div id="textId">
    </div>
    <script>
      let element = document.getElementById("textId");
      function createTextUnder(element, html) {
        // create text element
        let text = document.createElement('div');
        // it’s recommended to apply here a css class for the style 
        text.style.cssText = "position:fixed; color: green; font-size: 25px";
        // assign coordinates, don't forget "px"!
        let coords = element.getBoundingClientRect();
        text.style.left = coords.left + "px";
        text.style.top = coords.bottom + "px";
        text.innerHTML = html;
        return text;
      }
      let text = createTextUnder(element, 'Welcome to W3Docs');
      document.body.append(text);
      setTimeout(() => text.remove(), 3000);
    </script>
  </body>
</html>

You can modify the code for showing the message at the right, left, below, applying CSS animation, and more. Having all the coordinates and sizes of the element makes it easily doable.

But, the message flows away from the button when the page is scrolled. To modify that, it’s necessary to apply document-based coordinates and position:absolute.

Document Coordinates

The document-relative coordinates begin from the upper-left corner rather than the window.

In CSS, the window coordinates match position:fixed. On the contrary, the document coordinates are like position:absolute on top.

No standard method exists for getting the document coordinates of an element. But, it can be written straightforwardly.

You can connect two coordinate systems with the following formula:

  • pageY = clientY plus the height of the document scrolled-out vertical part.
  • pageX = client plus the width of the document scrolled-out horizontal part.

The getCoords(elem) function takes the window coordinates from elem.getBoundingClientRect() adding the current scroll to them, like this:

function getCoords(elem) {
  let box = elem.getBoundingClientRect();
  return {
    top: box.top + window.pageYOffset,
    left: box.left + window.pageXOffset
  };
}

In the example above, it is used with position:absolute . Afterward, the message stays next to the element on the scroll.

The changed createMessageUnder function will look like this:

let element = document.getElementById("textId");
function createTextUnder(element, html) {
  let text = document.createElement('div');
  text.style.cssText = "position:absolute; color: red";
  let coords = getCoords(element);
  text.style.left = coords.left + "px";
  text.style.top = coords.bottom + "px";
  text.innerHTML = html;
  return text;
}

Summary

In this chapter, we covered the ways of working with coordinates in JavaScript. So, each point on the pages should have coordinates such as relative to the window (elem.getBoundingClientRect()) and relative to the document (elem.getBoundingClientRect()+ the current page scroll).

The window coordinates properly work with position:fixed, and the document coordinates- with position:absolute.

Coordinates can have both advantages and disadvantages, hence at times, you may need to use CSS position absolute and fixed.




Do you find this helpful?

Related articles