Image zoom in 구현하기 - 2

jh_leitmotif·2021년 10월 1일
1

Frontend 개인 공부

목록 보기
3/24
post-thumbnail

🧐 개요

요즘 Node와 React를 이용해 웹 쇼핑몰 페이지를 클로닝 아닌(?) 클로닝을 하며 공부 중입니다.

그 중, 여러 쇼핑몰 사이트에서 지원하는 기능 중 하나인

이미지에 커서를 가져다 댔을 때, 자동으로 zoom in 되어 상세히 볼 수 있게 하는 것을

구현해보았습니다.

첫 번째 포스트는 전체적인 틀을 잡았고

이번 포스트에서는 이미지가 zoom in 된 결과 창을 렌더링하는 부분을 정리해봅니다.

📋 결과 창 레이아웃 넣기

첫 번째 포스트의 조잡한(?) 그림을 다시 가져왔습니다.

여기서 신경써야될 것은 상품 정보 섹션 위에 덮여질 태그의 position일 뿐입니다.

부모 요소는 productHeader 인데 딱히 정한 포지션 속성이 없는 그저 영역 구별용 요소입니다.

따라서 position: absolute을 통해 브라우저 기준으로 넣어지도록 한 뒤

width, height 값은 옆에 있는 img 태그와 통일시켜주고

margin은 대충 보기 이쁘게 해줍니다.

display를 정의하지 않으면 block으로 부여되어 밑으로 내려갈 수도 있기 때문에

inline-block처리를 통해 제품 이미지와 같은 선 상에 놓여지도록 했습니다.

성공적으로 productInfo div 태그 위에 imageZoom이 렌더링된 것이 확인되었습니다!

📋 커서 영역 레이아웃

먼저 React 사용자답게(?) 사용자 커서의 x, y 좌표 값을 state로 선언합니다.

위의 결과 창과 마찬가지로 커서 영역은 이미지 태그 위에 그려져야합니다.

width와 height는 영역을 5배 확대할테니 이미지 너비/높이의 나누기 5인 50입니다.

❕ onMouseMove event

1. 커서 영역 렌더링

커서 영역을 그리려면 이미지 위에 마우스가 움직일 때 x, y좌표가 업데이트되어야 합니다.

즉, onMouseMove 이벤트를 추가합니다.

위와 같이 마우스가 움직일 때, 페이지 기준으로 x, y좌표를 업데이트 시켜주면?

이렇게 됩니다!

다만 저는 마우스 커서가 중앙으로 오게 하고 싶었습니다.

cursorX, cursorY는 커서 영역의 left와 top 값에 대응됩니다.

따라서 단순히 width, height의 절반인 25를 빼주기만 하면?

아까와 다르게 커서를 기준으로 네모가 움직이는 것을 볼 수 있습니다.

2. 이미지 안 밖 설정

img element의 onMouseMove에 삽입된 조건입니다.

만약 요소의 태그가 IMG라면 커서 영역을 여러 옵션과 같이 보여줍니다.
물론, 결과 창(imageZoomRef) 또한 보여줍니다.

첫 번째 포스트에 언급했듯이 onMouseMove는 들어갔다 나왔다가 혼자서 막 다합니다..!

그러므로 img 태그를 감싸는 div 태그의 padding을 이용해 간격을 만들어주고

해당 간격에 마우스가 닿았을 때 tagName이 DIV로 인식되면 커서 영역과 결과 창을 모두 숨깁니다.

📑 결과 창 렌더링하기

의도가 제대로 반영되기위해 우선 건드려야할 속성을 생각해보았습니다.

1. 결과 창의 배경 이미지 경로
2. 결과 창과 커서 영역간의 비율, 결과 이미지의 크기
3. 결과 창의 포지션 잡기

1. 결과 창의 배경 이미지 경로

결과 창에는 제품의 배경 이미지가 들어와야 합니다.

크게 언급할 것이 없네요!
제품 데이터를 받아왔을 때 실행되는 useEffect 내부에서
결과 창의 배경 이미지를 제품 데이터에 있는 이미지 경로로 설정해줬습니다.

2. 결과 창과 커서 영역간의 비율, 이미지의 크기

결과 ref = imageZoomRef
커서 ref = cursorBoxRef
이미지 ref = productImageTagRef

결과 창에는 커서 영역이 확대되어 보여야합니다.

확대될 비율을 알아야 결과 창에 보여질 배경 이미지의 크기를 정할 수가 있으므로

offsetWidth와 offsetHeight를 이용하여
margin, padding 등등을 모두 포함한 결과창 대비 커서 영역의 너비와 높이 비율을 계산해둡니다.


그리고 이미지의 너비와 높이에 비율을 곱하면 확대된 영역의 크기가 확인될 겁니다.

확대되는 것이 확인되었습니다!

3. 결과 창의 포지션 잡기

마지막입니다!
요지는 결과 창에는 커서 영역에 해당하는 곳이 확대되어 보여야합니다.

우선 페이지에 이미지만 있다고 가정했을 때의 커서 위치를 계산해보았습니다.

event.target.getBoundingClientRect()
 -> 이를 통해 이미지 태그가 페이지에서 어떤 좌표점에 있는지 확인할 수 있습니다.

(0,0) 좌표에서 페이지가 뻗어나간다고 생각했을 때,

x좌표는 현재 커서의 x좌표에서 이미지의 맨 왼쪽 x값을 빼면 구할 수 있습니다.

마찬가지로, y좌표도 동일하게 구합니다.

혹시나 scrollX, Y값이 영향을 미칠 수 있으니 같이 빼줍니다.

더불어 커서 기준으로 그려진 영역이 있다는 것을 기억해야 합니다.

계산한 x,y 좌표 값에서 영역 너비의 반만큼만 빼면

(0,0) 기준의 좌표 값을 구할 수 있습니다.

😡 잘못된 접근?

아! 다 됐겠지?

하고서는

위와 같이 backgroundPosition에 지정을 해줬더니..

의도와 반대로 정반대쪽의 영역을 확대하고 있는 것입니다.

잘못된 이유는 backgroundPosition에 대한 잘못된 이해에 있었습니다.

예를 들어 위와 같은 경우, 버튼 안에 React 이미지가 2개 들어가있는 것으로 보이지만

사실은..!

위와 같이 버튼의 영역에 해당하지 않는 곳에 이미지가 바둑판처럼 자리잡고 있는 것입니다.

만약 이 상태에서 positionX,Y값을 양수로 넣어버리면?

오히려 이렇게 이미지가 영역 밖으로 밀려나게 되는 것입니다.

즉, 결과 창의 영역보다 상품 이미지는 더 큰 영역에 자리잡고 있었던 것이고

position을 양수로 하게 되면 오히려 영역 밖으로 밀어내는 꼴이 되는 것입니다.

따라서 음수로 전환하여 마무리할 수 있게 되었습니다.

✔ 문제점!

커서 영역이 움직일 때, 렌더링이 계속 되어 끊기는 현상이 일어난다.

바로 위의 이미지에서 알 수 있듯, 커서를 움직일 때 끊김이 있습니다.

이는 커서 영역의 left, right값이 현재 커서 좌표에 따라 달라지면서 렌더링이 반복되는 것에 기인합니다.

그러므로 끊김 현상은 커서 영역을 보여주지 않으니 사라졌습니다.

위의 기존 코드에서

커서 영역이 hidden 상태로 여전히 남겨두도록 만들면

left와 top 값은 열심히 바뀌지만 hidden인 채로 머물기에 렌더링되느라 끊기는 현상이 없습니다.

실제로 레퍼런스차 살펴본 바,

무신사스토어 ( 이미지 클릭시 모달 팝업 후, 커서 이동으로 확대. 닫기 버튼으로 모달 닫기 )
SSF SHOP ( 클릭시 전체 페이지로 확대되며, y축으로만 확인 가능 )
코오롱몰 ( 사진1, 사진2 모두 zoom in, out 가능. 사진1은 사진2영역, 사진2는 사진1영역에 출력 )

등 따로 커서 영역을 표시해서 보여주지는 않았습니다.


마무리

실은 velog 탐방 중, 어떤 분께서 스타벅스 웹페이지를 예시로

직접 구현하신 것을 보면서 꼭 내 것으로 만들어본다!! 하는 생각이 있었는데

다행(?)스럽게도 무언가 비슷한 것을 만든 것 같습니다.

profile
Define the undefined.

0개의 댓글