web developer

[javaScript] 절대 좌표, 상대 좌표 구하기 [스크롤, 마우스 이벤트] 본문

JavaScript

[javaScript] 절대 좌표, 상대 좌표 구하기 [스크롤, 마우스 이벤트]

trueman 2024. 3. 18. 21:29
728x90
728x90

(1) 뷰포트 정의


뷰포트(viewport)란 웹 페이지를 볼 때 보이는 영역을 말합니다.

모바일 기기에서는 디스플레이의 크기가 작아서 뷰포트가 작은 경우가 많습니다. 이 경우, 웹 페이지의 컨텐츠가 작게 보일 수 있고, 가독성이 떨어질 수 있습니다. 이를 해결하기 위해 뷰포트를 조정할 수 있습니다. 뷰포트는 HTML 문서의 <meta> 태그를 이용하여 조정할 수 있습니다.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

위 코드에서 width=device-width는 뷰포트의 너비를 기기의 너비로 설정한다는 의미입니다. initial-scale=1.0은 페이지 로딩 시 초기 축소/확대 비율을 1로 설정한다는 의미입니다. 이렇게 설정하면, 모바일 기기에서 웹 페이지가 자연스럽게 보이게 됩니다.

 

뷰포트를 설정할 때 주의할 점은, 뷰포트를 설정하면 반드시 미디어 쿼리를 사용하여 웹 페이지를 반응형으로 만들어야 한다는 점입니다. 그렇지 않으면 뷰포트의 크기가 고정되어 있어서 웹 페이지가 작게 보일 수 있습니다.


(2-1) getBoundClientRect() 메서드


getBoundClientRect() 메서드는 HTML 요소(Element)의 크기와 현재 뷰포트에서의 요소의 상대적인 위치 정보를 반환합니다.

 

See the Pen Untitled by 안중현 (@drkdcoaa-the-vuer) on CodePen.


(2-2) getBoundClientRect() 반환된 값


VIEWPORT

  1. getBoundingClientRect() 메서드의 반환되는 값은 요소 박스에 대한 크기 정보와 위치 정보입니다.
  2. 위치는 현재 보여지는 viewport에서의 상대적인 위치가 됩니다.
  3. 그래서 getBoundingClientRect() 의 요소의 위치는 고정값이 아니라 문서가 브라우저에서 스크롤 될 때 마다 값이 변하게 됩니다.
  4. 요소의 위치 값들은 현재 viewport가 표시하는 곳의 좌측 위를 (0,0) 하여 구하는 상대적 위치이므로 스크롤 될 때 마다 요소의 위치값은 계속 변하게 됩니다.
  5. width,height는 padding과 border-width가 포함된 값입니다. 그래서 width, height를 이용해 가공하기 전에 box-sizing 속성을 확인해야합니다. box-sizing:border-box 가 작업하기 편할 수 있습니다.

(3) 문서 내 요소의 상대적인 위치 및 스크롤 위치


offset().left, offset().top

  1. offset().left :
    • [기준] 특정 요소의 문서 왼쪽 위치
    • [반환] 문서 영역 내 특정 요소의 상대적인 위치
    • offset().left은 jQuery의 메서드로, 특정 요소의 문서 왼쪽에서의 위치를 반환합니다.
    • 해당 요소가 문서의 왼쪽에서 얼마나 떨어져 있는지를 나타냅니다.
  2. offset().top :
    • [기준] 특정 요소의 문서 위쪽 위치
    • [반환] 문서 영역 내 특정 요소의 상대적인 위치
    • offset().top은 jQuery의 메서드로, 특정 요소의 문서 위쪽에서의 위치를 반환합니다.
    • 해당 요소가 문서의 맨 위에서 얼마나 떨어져 있는지를 나타냅니다.

* var popup = document.getElementById('popup') 을 가정하면 아래와 같이 쓸 수 있습니다.

→ 'popup.offsetLeft' == '$(popup).offset().left


window.scrollX, window.scrollY

  1. window.scrollX :
    • [기준] 브라우저 창의 왼쪽
    • [반환] 현재 문서가 왼쪽에서부터 수평으로 스크롤된 픽셀 수
    • scrollX는 window 객체의 프로퍼티로, 현재 문서가 수평으로 스크롤된 픽셀 수를 나타냅니다.
    • scrollX는 읽기 전용이며, 페이지의 왼쪽으로부터 스크롤된 픽셀 수를 반환합니다.
  2. window.scrollY :
    • [기준] 브라우저 창의 위쪽
    • [반환] 현재 문서가 위쪽에서부터 수직으로 스크롤된 픽셀 수
    • scrollY는 window 객체의 프로퍼티로, 현재 문서가 수직으로 스크롤된 픽셀 수를 나타냅니다.
    • scrollY는 읽기 전용이며, 페이지의 위쪽으로부터 스크롤된 픽셀 수를 반환합니다.

window.pageXOffset, window.pageYOffset

  1. window.pageXOffset :   
    • [기준] 브라우저 창의 왼쪽
    • [반환] 현재 문서가 왼쪽에서부터 수평으로 스크롤된 픽셀 수
    • pageXOffset 역시 window 객체의 프로퍼티로, 현재 문서가 수평으로 스크롤된 픽셀 수를 나타냅니다.
    • scrollX와 동일한 값을 반환하며, pageXOffset은 scrollX의 브라우저 호환성을 위한 다른 이름입니다.
  2. window.pageYOffset :
    • [기준] 브라우저 창의 위쪽
    • [반환] 현재 문서가 위쪽에서부터 수직으로 스크롤된 픽셀 수
    • pageYOffset 역시 window 객체의 프로퍼티로, 현재 문서가 수직으로 스크롤된 픽셀 수를 나타냅니다.
    • scrollY와 동일한 값을 반환하며, pageYOffset은 scrollY의 브라우저 호환성을 위한 다른 이름입니다.

document.documentElement.scrollLeft, document.documentElement.scrollTop

  1. document.documentElement.scrollLeft :
    • [기준] 문서의 최상위 요소인 <html> 요소의 왼쪽부터
    • [반환] 현재 문서가 쪽에서부터 가로로 스크롤된 픽셀 수
    • scrollLeft는 문서가 가로로 스크롤될 때 스크롤바가 왼쪽에서부터 얼마나 이동했는지를 나타냅니다. 문서가 오른쪽으로 스크롤될수록 값이 증가합니다.
  2. document.documentElement.scrollTop :   
    • [기준] 문서의 최상위 요소인 <html> 요소의 위쪽부터
    • [반환] 현재 문서가 위쪽에서부터 세로로 스크롤된 픽셀 수
    • scrollTop은 문서가 세로로 스크롤될 때 스크롤바가 위에서부터 얼마나 이동했는지를 나타냅니다. 문서가 아래로 스크롤될수록 값이 증가합니다.

* 이 속성들은 window.pageXOffset 및 window.pageYOffset와 유사하지만, 다음과 같은 차이가 있습니다.
→ window.pageXOffset 및 window.pageYOffset은 브라우저 창 자체의 스크롤 위치를 나타냅니다. document.documentElement.scrollTop 및 document.documentElement.scrollLeft는 문서의 최상위 요소인 <html> 요소의 스크롤 위치를 나타냅니다.


(4) 절대 좌표를 구하는 방법 


대부분 offset API로 절대좌표를 구하지만, 포지셔닝 정책에 따라 구해지는 값이 달라지므로 안전하게 구하는 방법은 다음과 같습니다.

  1. 요소의 상대 좌표를 구합니다. 이는 getBoundingClientRect() 메서드를 사용하여 요소의 상대적인 위치와 크기를 반환합니다.
  2. 현재 문서의 스크롤 위치를 고려하여 절대 좌표를 계산합니다.
    • rect.top : 요소의 위쪽 경계와 브라우저의 위쪽 경계 사이의 거리 
    • window.pageYOffset, document.documentElement.scrollTop : 문서의 상단에서 스크롤된 픽셀 수
    • 'rect.top + window.pageYOffset' : 요소의 상단 가장자리에서 문서의 상단 가장자리까지의 거리 = 요소의 절대 Y 좌표

이러한 단계를 반영한 자바스크립트 코드 예제입니다:

function getAbsoluteCoordinates(element) {
    const rect = element.getBoundingClientRect();
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 
    const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
    
    // 스크롤된 컨텐츠의 길이와 viewport 기준의 상대좌표를 연산하여 절대좌표를 구합니다.
    const absoluteTop = rect.top + scrollTop;
    const absoluteLeft = rect.left + scrollLeft;
    
    return { top: absoluteTop, left: absoluteLeft };
}

// 요소를 선택하고 절대 좌표를 가져옵니다.
const element = document.getElementById('yourElementId');
const absoluteCoordinates = getAbsoluteCoordinates(element);
console.log('절대 좌표:', absoluteCoordinates);

offsetAPI를 사용하기 위해서는 부모 요소가 'position:relative' 이 되어있어야 합니다. relative가 아니라면 해당API는 부모 요소기준이 아닌 상위요소를 계속 탐색하여 relative가 있는 부모를 기준으로 좌표값을 계산합니다.
상위요소들 모두 relative 포니셔닝이 아니라면 컨텐츠의 시작지점 즉, '절대위치' 값을 리턴하게 됩니다.


(5) 마우스 이벤트 시 위치


event.clientX, event.clientY

  1. event.clientX :
    • [기준] 마우스 이벤트 발생 위치의 X 좌표
    • [반환] 문서 영역 내 상대적인 위치
    • event.clientX는 마우스 이벤트가 발생한 문서 영역(클라이언트 영역) 내의 X 좌표를 나타냅니다.
    • 브라우저 창의 왼쪽 상단을 기준으로 마우스 이벤트가 발생한 위치를 상대적인 좌표로 제공합니다.
    • 페이지 스크롤에 영향을 받지 않으므로, 문서의 스크롤 상태에 관계없이 마우스 이벤트가 발생한 정확한 위치를 파악할 수 있습니다.
  2. event.clientY :
    • [기준] 마우스 이벤트 발생 위치의 Y 좌표
    • [반환] 문서 영역 내 상대적인 위치
    • event.clientY는 마우스 이벤트가 발생한 문서 영역(클라이언트 영역) 내의 Y 좌표를 나타냅니다.
    • 브라우저 창의 상단을 기준으로 마우스 이벤트가 발생한 위치를 상대적인 좌표로 제공합니다.

event.pageX, event.pageY

  1. event.pageX :
    • [기준] 마우스 이벤트 발생 위치의 X 좌표
    • [반환] 문서 전체 내 상대적 위치
    • 문서의 왼쪽 상단을 기준으로 마우스 이벤트가 발생한 위치를 상대적인 좌표로 제공합니다.
    • 페이지 스크롤에 영향을 받으므로, 페이지가 스크롤되거나 확대/축소되었을 때의 정확한 위치를 파악할 수 있습니다.
  2. event.pageY :
    • [기준] 마우스 이벤트 발생  위치의 Y 좌표
    • [반환] 문서 전체 내의 상대적 위치
    • 문서의 상단을 기준으로 마우스 이벤트가 발생한 위치를 상대적인 좌표로 제공합니다.

event.screenX, event.screenY

  1. event.screen:
    • [기준] 화면 전체 내에서의 마우스 이벤트 발생 위치의 X 좌표
    • [반환] 화면 전체 내의 절대적 위치
    • 화면의 왼쪽 상단을 기준으로 마우스 이벤트가 발생한 위치를 절대적인 좌표로 제공합니다.
    • 해상도와 무관하게 화면의 위치를 나타내므로, 다중 모니터 환경에서도 유용하게 사용될 수 있습니다.
  2. event.screenY :
    • [기준] 화면 전체 내에서의 마우스 이벤트 발생 위치의 Y 좌표
    • [반환] 화면 전체 내의 절대적 위치
    • 화면의 상단을 기준으로 마우스 이벤트가 발생한 위치를 절대적인 좌표로 제공합니다.

(6) 마우스 이동에 따른 툴팁 위치 조정 


툴팁의 텍스트 박스를 마우스 커서의 중앙에 위치시키려면 다음과 같이 할 수 있습니다. 여기서는 마우스 이벤트를 사용하여 툴팁의 위치를 동적으로 조정합니다.

// 마우스 이벤트 핸들러 등록
document.addEventListener('mousemove', function(e) {
    // 마우스 위치 가져오기
    var mouseX = e.clientX;
    var mouseY = e.clientY;

    // tooltip 요소 가져오기
    var tooltip = document.getElementById('tooltip');

    // 툴팁의 너비와 높이 가져오기
    var tooltipWidth = tooltip.offsetWidth;
    var tooltipHeight = tooltip.offsetHeight;

    // 마우스 커서의 중앙 위치 계산
    var tooltipX = mouseX - (tooltipWidth / 2);
    var tooltipY = mouseY - (tooltipHeight / 2);
    
    // 마우스 커서 위치 위로 설정
    tooltipY = (tooltipY - 40); 

    // tooltip 위치 설정
    tooltip.style.left = tooltipX + 'px';
    tooltip.style.top = tooltipY + 'px';
    // $('.tooltip').css({ top: tooltipY, left: tooltipX });
});

위 코드는 마우스 이벤트를 감지하여 마우스 커서의 중앙에 툴팁을 배치합니다. 이를 위해 툴팁의 너비와 높이를 고려하여 마우스 좌표를 조정합니다. 이제 툴팁이 마우스 커서의 중앙에 표시될 것입니다.


(7-1) 스크롤 위치를 고려하지 않고, 팝업 창을 이동시키는 방법  


팝업 창을 마우스로 클릭하여 이동할 때, 팝업 창의 새로운 위치를 정확히 결정하기 위해서는 마우스 이벤트를 사용하여 마우스가 클릭된 위치와 팝업 창의 이동 거리를 계산해야 합니다. 이를 통해 팝업 창의 새로운 위치를 결정할 수 있습니다.

일반적으로 다음과 같은 절차를 따릅니다:

  1. 마우스 다운(mouse down) 이벤트를 감지하여 팝업 창이 마우스로 클릭되었을 때의 시작 위치를 기록합니다.
  2. 마우스 이동(mouse move) 이벤트를 감지하여 마우스가 이동한 거리를 계산합니다.
  3. 팝업 창을 이동한 만큼 이동 거리만큼 새로운 위치로 이동시킵니다.
  4. 마우스 업(mouse up) 이벤트를 감지하여 마우스 클릭을 끝내고 이벤트 리스너를 제거합니다.
let isDragging = false;
let startX, startY;
let popup = document.getElementById('popup');

// 팝업 창을 클릭하여 이동할 때
popup.addEventListener('mousedown', function(event) {
    isDragging = true;
    // 'popup.offsetLeft' == '$(popup).offset().left' → 같은 의미이다.
    startX = event.clientX - popup.offsetLeft; 
    startY = event.clientY - popup.offsetTop;
});

// 팝업 창을 이동할 때
document.addEventListener('mousemove', function(event) {
    if (isDragging) {
        let newLeft = event.clientX - startX;
        let newTop = event.clientY - startY;
        popup.style.left = newLeft + 'px';
        popup.style.top = newTop + 'px';
    }
});

// 마우스 클릭을 끝내면
document.addEventListener('mouseup', function(event) {
    isDragging = false;
});

팝업 창을 마우스로 클릭하고 이동할 때의 이벤트를 처리하고, 마우스 이동 거리를 기록하여 팝업 창을 새로운 위치로 이동시킵니다. 이 코드는 팝업 창을 수평 및 수직으로 자유롭게 이동할 수 있게 합니다.


(7-2) 스크롤 위치를 고려하여 팝업 창을 올바르게 이동시키는 방법  


스크롤 위치를 고려하여 팝업 창을 올바르게 이동시키기 위해서는 window.pageXOffsetwindow.pageYOffset를 사용하여 스크롤된 만큼을 보정해야 합니다.

let isDragging = false;
let startX, startY;
let popup = document.getElementById('popup');

// 팝업 창을 클릭하여 이동할 때
popup.addEventListener('mousedown', function(event) {
    isDragging = true;
    startX = event.clientX + window.pageXOffset - popup.offsetLeft;
    startY = event.clientY + window.pageYOffset - popup.offsetTop;
});

// 팝업 창을 이동할 때
document.addEventListener('mousemove', function(event) {
    if (isDragging) {
        let newLeft = event.clientX + window.pageXOffset - startX;
        let newTop = event.clientY + window.pageYOffset - startY;
        popup.style.left = newLeft + 'px';
        popup.style.top = newTop + 'px';
    }
});

// 마우스 클릭을 끝내면
document.addEventListener('mouseup', function(event) {
    isDragging = false;
});

mousedown 이벤트 핸들러에서 startXstartY를 계산할 때 스크롤된 만큼을 보정해주었습니다. 그리고 mousemove 이벤트 핸들러에서 새로운 위치를 계산할 때도 마찬가지로 스크롤된 만큼을 보정하여 새로운 위치를 계산합니다. 이렇게 함으로써 스크롤된 문서 내에서도 팝업 창을 정확하게 이동시킬 수 있습니다.


출처 : https://mommoo.tistory.com/85 

출처 : https://webisfree.com/2014-09-07/%5Bjquery%5D-%EC%A0%88%EB%8C%80%EC%A2%8C%ED%91%9C-%EB%B0%8F-%EC%83%81%EB%8C%80%EC%A2%8C%ED%91%9C-%ED%99%95%EC%9D%B8-%EB%B0%8F-%EC%9D%B4%EB%8F%99%ED%95%98%EA%B8%B0-offset()-position()

728x90
728x90