특정 위치를 클릭하면 점이 찍히고 위치정보를 저장해야 하는 기능을 만들어야 하는 일이 생겼다.
더 정확히는 클릭하면 위 사진처럼 빨간점이 찍히고 빨간점이 네모로부터 얼마나 떨어져있는지에 대한 값을 구해야했다.
위 처럼 클릭 이벤트의 절대좌표에서 네모 엘리먼트의 절대좌표를 뺀다면 클릭한 위치가 엘리먼트로부터 얼마나 떨어져 있는지를 알 수 있다.
const RecordClick = e => {
// 여기서의 이벤트는 클릭 이벤트 객체
(이벤트 리스너의 콜백함수로 들어갈 함수)
const sidePosition = {
X: Math.floor(e.target.getBoundingClientRect().left + window.pageXOffset),
Y: Math.floor(e.target.getBoundingClientRect().top + window.pageYOffset),
};
// 클릭한 엘리먼트의 절대좌표
// .getBoundingClientRect().left 뷰포트 기준 X값 top은 Y 값
// pageOffset은 오프셋으로부터 계산한 스크롤 가로길이
const clickPosition = {
X: Math.floor(e.clientX) + window.pageXOffset,
Y: Math.floor(e.clientY) + window.pageYOffset,
};
// 클릭 이벤트의 좌표 어차피 서로 뺄거라 기준만 맞추면 됨
}
콘솔을 찍어보면 페이지 기준 엘리먼트 값의 좌표와
페이지 기준 클릭 이벤트의 좌표가 나온다. 클릭값에서 엘리먼트 값을 빼주면 엘리먼트 기준 상대좌표를 구할 수 있다.
상대 좌표를 구한다면 그 위의 점을 찍을수가 있는데
상대좌표 자체가 '기준점으로부터 좌측으로 얼마 상단으로부터 얼마 떨어져 있는지를 픽셀단위로 구한 값'
이므로 기준점을 relative로 한 absolute의 top과 left값으로 넣기만 하면 해당 클릭점에 점을 찍을 수 있다.
하지만 나는 세부 픽셀이 달라도 동일한 위치에 점이 찍히게 하고 싶어서 해당 상대좌표의 값이 전체 엘리먼트의 몇 퍼센트인지를 계산하고 top left값에 역산하여 넣기로 했다.
const ratio = {
X: clickPosition.X - sidePosition.X,
Y: clickPosition.Y - sidePosition.Y,
};
// 상대 좌표
const XPer = (ratio.X / Number(pullWidth)) * 100;
const YPer = (ratio.Y / Number(pullHeight)) * 100;
const xyPer = { XPer: XPer.toFixed(2), YPer: YPer.toFixed(2) };
setClickArr([...clickArr, xyPer]);
// 스테이트 배열에 넣어준다
// 백분율
다음과 같은 형식으로 map을 돌렸다. 720 1920 자리에는 props로 높이와 길이를 받아와서 컴포넌트 형식으로 사용하게 리팩토링할 예정.
크기가 달라도 상대적인 퍼센트로 계산하여 점을 찍기 때문에 균일한 위치에 점이 찍힌다.
//
낯선 개념이였지만 처음에 의도한 결과물이 나와서 만족스러웠고 재밌었다.
그리고 일에 열중하느라 저번달 회고를 못써버렸다..