본문 바로가기
JavaScript

JavaScript] Coordinates (element 좌표)

by Fastlane 2022. 11. 17.
728x90
반응형

출처 : https://javascript.info/coordinates

elements를 이동시키기 위해서, 우리는 좌표에 익숙해져야 한다. 

대부분의 JavaScript  함수들은 두 좌표 시스템 중 하나를 사용한다. 

  1. Relative to the window - position:fixed와 유사하다. window top/left edge로부터 계산한다. 
    • 이러한 좌표를 clientX/clientY로 나타낸다. 
  2. Relative to the document - position:absolute와 유사하다. document top/left edge로부터 계산한다. 
    • 이러한 좌표를 pageX/pageY로 나타낸다.

page를 맨처음으로 스크롤할때 window의 top/left corner는 document의 top/left corner로 같다. 하지만 document를 이동하면, document-relative 좌표는 그대로이지만, window를 지나 elements가 이동함에 따라 window-relative 좌표는 달라진다. 

 

아래 사진은 스크롤 이전(왼쪽)과 스크롤 이후(오른쪽)에 두 좌표를 보여준다. 

document를 스크롤할때

  • pageY - document top으로부터 계산되므로, document-relative 좌표는 동일하다. 
  • clientY - 동일한 지점이 window top에 가까워짐에 따라 좌표가 변경된다. 

Element coordinates: getBoundingClientRect

elem.getBoundingClientRect()함수는 element를 감싸는 최소한의 사각형을 위한 window coordinates를 반환한다. 

 

  • left = x
  • top = y
  • right = x + width
  • bottom = y + height

좌표는 -가 될 수 있다. 예를들어 element가 스크롤되어 window 위에 있는 경우 elem.getBoundingClientRect().top은 -값이다. 

 

elementFromPoint(x, y)

document.elementFromPoint(x, y)는 window coordinates (x, y)에서 가장 감싸져있는 element를 반환한다. 

// window의 중간에 있는 element를 강조하고 tag를 output한다. 

let centerX = document.documentElement.clientWidth / 2;
let centerY = document.documentElement.clientHeight / 2;

let elem = document.elementFromPoint(centerX, centerY);

elem.style.background = "red";
alert(elem.tagName);

 

scroll 위치에 따라 element는 변경된다. 

document.elementFromPoint(x, y)는 (x, y)가 visible area에 있을때만 동작하며 그 외에는 null을 반환한다. 

let elem = document.elementFromPoint(x, y);
// if the coordinates happen to be out of the window, then elem = null
elem.style.background = ''; // Error!

Using for “fixed” positioning

무언가의 위치를 정하기 위해서 우리는 좌표가 필요하다. 

element주위에 뭔가 표시하기 위해서, getBoundingClientRect를 사용하여 그것의 좌표를 알아내고 CSS position을 지정한다. 

 

예를들어, createMessageUnder(elem, html)은 elem아래에 메시지를 보여준다. 

let elem = document.getElementById("coords-show-mark");

function createMessageUnder(elem, html) {
  // create message element
  let message = document.createElement('div');
  // better to use a css class for the style here
  message.style.cssText = "position:fixed; color: red";

  // assign coordinates, don't forget "px"!
  let coords = elem.getBoundingClientRect();

  message.style.left = coords.left + "px";
  message.style.top = coords.bottom + "px";

  message.innerHTML = html;

  return message;
}

// Usage:
// add it for 5 seconds in the document
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);

page를 스크롤하면 메시지는 document.getElementById("coords-show-mark")과 멀어진다. 왜냐하면 message element는 position:fixed하므로 page가 스크롤되어도 window의 동일한 위치를 유지한다. 

이를 수정하기 위해서 우리는 document-based 좌표와 position:absolute를 사용해야 한다. 

 

Document coordinates

element의 document coordinates를 얻기위한 공식함수는 없다. 두 좌표는 공식으로 연결되어 있다. 

  • pageY = clientY + height of the scrolled-out vertical part of the document
  • pageX = clientX + width of the scrolled-out horizontal part of the document

함수 getCoords(elem)은 elem.getBoundingClientRect()함수로 window 좌표를 알아낸다음 현재 scroll을 더한다. 

let elem = document.getElementById("coords-show-mark");

// get document coordinates of the element
function getCoords(elem) {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + window.pageYOffset,
    right: box.right + window.pageXOffset,
    bottom: box.bottom + window.pageYOffset,
    left: box.left + window.pageXOffset
  };
}

function createMessageUnder(elem, html) {
  let message = document.createElement('div');
  message.style.cssText = "position:absolute; color: red";

  let coords = getCoords(elem);

  message.style.left = coords.left + "px";
  message.style.top = coords.bottom + "px";

  message.innerHTML = html;

  return message;
}

// Usage:
// add it for 5 seconds in the document
let message = createMessageUnder(elem, 'Hello, world!');
document.body.append(message);
setTimeout(() => message.remove(), 5000);

메시지는 스크롤하여도 element근처에 위치한다. 

Summary

page의 어느 지점이든 아래 좌표를 갖는다. 

  • Relative to the window - elem.getBoundingClientRect()
  • Relative to the document - elem.getBoundingClientRect() 더하기 현재 page 스크롤

두좌표 모두 장단점이 있으니 필요에 따라 골라서 사용한다. 

728x90
반응형

댓글