Image Zoom on Hover ๐Ÿ” ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋งŒ๋“ค๊ธฐ

Wonkook Leeยท2021๋…„ 8์›” 26์ผ
69

Frontend Exercises

๋ชฉ๋ก ๋ณด๊ธฐ
6/7


(์œ„ ์ด๋ฏธ์ง€๊ฐ€ ๋‚ด๊ฐ€ ๋”ฐ๋ผ ๋งŒ๋“ค ์‹ค์ œ ๊ธฐ๋Šฅ)


Image Zoom on Hover ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋งŒ๋“ค๊ธฐ



์ œ์ž‘ ๋ชฉ์ 

Image Zoom on Hover ๊ธฐ๋Šฅ์€ ์‡ผํ•‘๋ชฐ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ํ”ํžˆ ๋ณด์ด๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ์ด๋ฏธ์ง€ ์˜์—ญ ์œ„์— ์˜ฌ๋ฆฌ๋ฉด ํ™•๋Œ€๋œ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ทฐํฌํŠธ๊ฐ€ ์ƒ๊ฒจ์„œ ๋ณ„๋„์˜ ๋ชจ๋‹ฌ์ด๋‚˜ ์œˆ๋„์šฐ ์—†์ด๋„ ์ด๋ฏธ์ง€๋ฅผ ์ž์„ธํžˆ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐ๋ž™์…˜ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

๊ณผ์ œ๋Š” ์•„๋‹ˆ์—ˆ์ง€๋งŒ JS๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜์„ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋Š” ์—ฐ์Šต์„ ํ•˜๊ณ ์‹ถ๊ณ , ๊ฐ์ฒด์˜ ์ขŒํ‘œ๋ฅผ ํ™œ์šฉํ•œ ํšจ๊ณผ๋Š” ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ๊ณต๋ถ€ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.




๋ฌธ์ œ์˜ ์ •์˜

๋ฌธ์ œ ํ•ด๊ฒฐ์€ ๋ฌธ์ œ๋ฅผ ์ •์˜ํ•˜๊ณ , ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ , ์ฐจ๊ทผ์ฐจ๊ทผ ํ•ด๊ฒฐํ•ด ๋‚˜๊ฐ€๋Š” ๊ณผ์ •์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์•„๋ž˜ ๋‹ค์„ฏ ๊ฐœ์˜ ๋ช…์ œ๊ฐ€ ์ด๋ฏธ์ง€ ์คŒ ๊ธฐ๋Šฅ์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™๋˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด์ด๋‹ค. ์•„๋ž˜ ๋ช…์ œ๋“ค์„ ๊ฐ€์ •ํ•˜๊ณ , ํ•˜๋‚˜์”ฉ ํ’€์–ด๊ฐ€๋Š” ๊ณผ์ •์„ ์†Œ๊ฐœํ•œ๋‹ค.

  • ์ด๋ฏธ์ง€ ์˜์—ญ ์œ„์— ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ์ด๋„ˆ ํ”„๋ ˆ์ž„๊ณผ ํ™•๋Œ€์ฐฝ์ด ๋‚˜ํƒ€๋‚œ๋‹ค.
  • ๋งˆ์šฐ์Šค ์ปค์„œ๊ฐ€ ์˜์—ญ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์ด๋„ˆ ํ”„๋ ˆ์ž„๊ณผ ํ™•๋Œ€์ฐฝ์€ ์‚ฌ๋ผ์ง„๋‹ค.
  • ์ด๋„ˆ ํ”„๋ ˆ์ž„์€ ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ๋”ฐ๋ผ ์›€์ง์ธ๋‹ค.
  • ์ด๋„ˆ ํ”„๋ ˆ์ž„์€ ์ด๋ฏธ์ง€ ์˜์—ญ ๊ฒฝ๊ณ„ ์•ˆ์—์„œ๋งŒ ์›€์ง์ธ๋‹ค.
  • ํ™•๋Œ€ ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ ์ด๋„ˆ ํ”„๋ ˆ์ž„ ์˜์—ญ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์—ฌ์•ผ ํ•˜๋ฉฐ, ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ๋„ ์›€์ง์ž„์€ ๋™๊ธฐํ™”๋˜์–ด์•ผ ํ•œ๋‹ค.
const zoomFrame = document.querySelector('.zoomFrame');
const zoomLens = document.querySelector('.zoomLens');
const zoomWindow = document.querySelector('.zoomWindow');



๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •


[๋ช…์ œ 1] ์ด๋ฏธ์ง€ ์˜์—ญ ์œ„์— ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ์ด๋„ˆ ํ”„๋ ˆ์ž„๊ณผ ํ™•๋Œ€์ฐฝ์ด ๋‚˜ํƒ€๋‚œ๋‹ค.

์œ ์ €์˜ ์–ด๋–ค ๋™์ž‘์„ ์ด๋ฒคํŠธ๋กœ์„œ ์ธ์‹ํ•  ๊ฒƒ์ธ์ง€ ์ •์˜ํ•˜๋ฉด ๋ฌธ์ œ ํ•ด๊ฒฐ์ด ์‰ฝ๋‹ค.

์คŒ ํ”„๋ ˆ์ž„ ์˜์—ญ์— ์ปค์„œ๊ฐ€ ์ง„์ž…ํ–ˆ๋‹ค + ๋งˆ์šฐ์Šค๊ฐ€ ์›€์ง์ธ๋‹ค = โ€˜mousemoveโ€™

zoomFrame.addEventListener('mousemove', callbackFn);

mouseenter ์˜์—ญ ์•ˆ์œผ๋กœ ์ง„์ž…ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€๋งŒ ๋”ฐ์ง€๊ณ , mouseover๋Š” ์ด๋ฒคํŠธ ์ž…๋ ฅ ์ฃผ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ๋„์—„๋„์—„์ด๋ผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค. ๋” ๋†’์€ FPS๋กœ ๋ถ€๋“œ๋Ÿฌ์šด ๋™์ž‘์ด ๊ฐ€๋Šฅํ•œ mousemove๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ์•„๋ž˜ ๋น„๊ต๋ฅผ ๋ณด๋ฉด ์ฐจ์ด๊ฐ€ ํ™•์—ฐํ•˜๋‹ค (์™ผ์ชฝ์ด mousemove)

์˜์—ญ ๋‚ด์˜ ์›€์ง์ž„์„ ์ œ์–ดํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๋ณ„๋„์˜ ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•œ๋‹ค.

function handleMouseMove(event) {
	zoomLens.style.display = 'block';
	zoomWindow.style.display = 'block';
}



[๋ช…์ œ 2] ๋งˆ์šฐ์Šค ์ปค์„œ๊ฐ€ ์˜์—ญ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์ด๋„ˆ ํ”„๋ ˆ์ž„๊ณผ ํ™•๋Œ€์ฐฝ์€ ์‚ฌ๋ผ์ง„๋‹ค.

์คŒ ํ”„๋ ˆ์ž„ ์˜์—ญ ๋ฐ–์œผ๋กœ ์ปค์„œ๊ฐ€ ๋‚˜๊ฐ„๋‹ค = โ€˜mouseleaveโ€™

zoomFrame.addEventListener('mouseleave', () => {
    zoomLens.style.display = 'none';
    zoomWindow.style.display = 'none';
});

๋งˆ์šฐ์Šค๊ฐ€ ๋Œ€์ƒ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์ด๋ฒคํŠธ๋กœ ์ธ์‹๋˜๋Š” mouseleave๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋งˆ์šฐ์Šค๊ฐ€ ์ฐฝ์„ ๋– ๋‚ ๋• ์š”์†Œ๋ฅผ ์ˆจ๊ธฐ๋Š” ์—ญํ• ๋ฐ–์— ์•ˆํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ธ์ž ์†์— ๊ทธ๋Œ€๋กœ ์„ ์–ธํ–ˆ๋‹ค.




[๋ช…์ œ 3] ์ด๋„ˆ ํ”„๋ ˆ์ž„์€ ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ๋”ฐ๋ผ ์›€์ง์ธ๋‹ค.

์š”์†Œ๊ฐ€ ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ๋”ฐ๋ผ๋‹ค๋‹ˆ๊ฒŒ ํ•˜๋ ค๋ฉด ๋งˆ์šฐ์Šค์˜ ์ขŒํ‘œ๋ฅผ ์•Œ์•„์•ผ ํ•œ๋‹ค. ๋ทฐํฌํŠธ์ƒ์˜ ์ขŒํ‘œ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์€ ์‰ฝ๋‹ค. ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ํ”„๋ ˆ์ž„์˜ ์œ„์น˜์™€ ๊ด€๊ณ„๋œ ์ƒ๋Œ€์  ๋งˆ์šฐ์Šค ์ขŒํ‘œ๋‹ค. ์ด ๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•ด์„œ ๋‚ด๊ฐ€ ์ฐพ์•„์•ผ ํ•  ๊ฒƒ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ๋ทฐํฌํŠธ ์† ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์ƒ๋Œ€ ์ขŒํ‘œ
  • ๋ทฐํฌํŠธ ์† ํ”„๋ ˆ์ž„ ์˜์—ญ์˜ ์ƒ๋Œ€์  ์œ„์น˜

๋ทฐํฌํŠธ ์† ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์ƒ๋Œ€ ์ขŒํ‘œ

์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์˜ ์ด๋ฒคํŠธ ๊ฐ์ฒด๋ฅผ ์ฝ˜์†”๋กœ ์ถœ๋ ฅํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
์—ฌ๊ธฐ์„œ ๋ˆˆ์—ฌ๊ฒจ๋ด์•ผ ํ•  ํ”„๋กœํผํ‹ฐ๋Š” clientX, clientY์™€ offsetX, offsetY๋‹ค.


clientX์™€ offsetX์˜ ์ฐจ์ด

clientX๋Š” ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €) ๊ธฐ์ค€์˜ ์ปค์„œ ์ขŒํ‘œ๊ฐ’์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. (X๋Š” ๊ฐ€๋กœ์ถ• Y๋Š” ์„ธ๋กœ์ถ• ๊ธฐ์ค€) ๋ธŒ๋ผ์šฐ์ € ํŽ˜์ด์ง€์—์„œ X์˜ ์ขŒํ‘œ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋ทฐํฌํŠธ ์ƒ๋‹จ์„ 0์œผ๋กœ ์ธก์ •ํ•œ๋‹ค. (๋ฌธ์„œ ์ „์ฒด ๊ธฐ์ค€์€ pageX)
offsetX๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๊ฑธ๋ ค์žˆ๋Š” DOM ์š”์†Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์ขŒํ‘œ๊ฐ’์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ด๋ก ์ ์œผ๋กœ๋Š” offsetX๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋Ÿด์‹ธํ•˜์ง€๋งŒ ์–ด์งธ์„œ์ธ์ง€ clientX์™€ offsetX์˜ ๊ฐ’์ด ๋˜‘๊ฐ™์•˜๋‹ค.
์–ด์ฐจํ”ผ ๋ทฐํฌํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ”„๋ ˆ์ž„ ์˜์—ญ์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„๋‚ด์–ด ๊ฐ’์„ ๋ณด์ •ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— client ์ขŒํ‘œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.


ํ™”๋ฉด์—์„œ ๋ณด์—ฌ์ง€๋Š” ์š”์†Œ์˜ ์ƒ๋Œ€์  ์œ„์น˜์™€ ํฌ๊ธฐ์ •๋ณด

getBoundingClientRect()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋Š” ํ™”๋ฉด์—์„œ ๋ณด์—ฌ์ง€๋Š” ์š”์†Œ์˜ ์ƒ๋Œ€์  ์œ„์น˜์™€ ํฌ๊ธฐ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃฌ ์ ์ด ์žˆ๋‹ค.


์˜์  ์กฐ์ ˆ

3D ๋ชจ๋ธ๋ง๊ณผ ๊ด€๋ จ๋œ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค๋ค„๋ณธ ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์•Œ ๊ฒƒ์ด๋‹ค. ๋ชจ๋“  ๊ฒƒ์€ ์˜ ์ฝค๋งˆ ์˜์—์„œ ์‹œ์ž‘๋œ๋‹ค๋Š” ๊ฒƒ์„. ๋‹ค๋ฅธ ์ ์ด๋ผ๋ฉด y์˜ ํฌ์ง€ํ‹ฐ๋ธŒ ๋ฐฉํ–ฅ์„ ๋ฐ˜์ „ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

์ขŒํ‘œ์™€ ์œ„์น˜ ์ •๋ณด๋ฅผ ์–ป์—ˆ์œผ๋‹ˆ ์ขŒ์ƒ๋‹จ์„ (0, 0)์œผ๋กœ ๋ณด์ •ํ•ด์•ผํ•œ๋‹ค. ํ”„๋ ˆ์ž„์˜ ์ขŒ์ƒ๋‹จ ๋ชจ์„œ๋ฆฌ ๋์— ๋งˆ์šฐ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋งˆ์šฐ์Šค์˜ (x, y)๊ฐ€ ํ”„๋ ˆ์ž„์˜ Rect ํ”„๋กœํผํ‹ฐ์˜ (left, top) ๊ฐ’๊ณผ ์ผ์น˜ํ•  ๊ฒƒ์ด๋‹ค. (๋‘˜ ๋‹ค ํ”„๋ ˆ์ž„์— ๋Œ€๋น„ํ•œ ์ƒ๋Œ€์  ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ)
๋”ฐ๋ผ์„œ ์˜์  ์กฐ์ ˆ๋œ ๋งˆ์šฐ์Šค ์ขŒํ‘œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

// DOMRect ๊ฐ์ฒด์—์„œ left, top๊ฐ’์„ ๋ถ„ํ•ดํ•˜์—ฌ ํ• ๋‹น
const {left, top} = zoomFrame.getBoundingClientRect();

// ๋งˆ์šฐ์Šค์˜ client ์ขŒํ‘œ์—์„œ ํ”„๋ ˆ์ž„์˜ ์œ„์น˜ ์ขŒํ‘œ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์˜์  ๋งž์ถ”๊ธฐ
const x = event.clientX - left;
const y = event.clientY - top;

์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ’์ด ์ž˜ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์š”์ฆ˜์€ ์›ํ•˜๋Š” ๊ฐ’์ด ๋“ค์–ด์˜ค๋Š”๊ฒƒ์„ ๋ณด๋Š” ๊ฒƒ๋งŒํผ ์งœ๋ฆฟํ•œ๊ฒŒ ๋˜ ์—†๋‹ค.


๋งˆ์šฐ์Šค ์ปค์„œ ์ขŒํ‘œ์™€ ์ด๋„ˆ ํ”„๋ ˆ์ž„ ์œ„์น˜ ์—ฐ๋™ํ•˜๊ธฐ

์œ„์—์„œ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น์œผ๋กœ ์ขŒํ‘œ๊ฐ’์„ ๋ณ€์ˆ˜ x์™€ y์— ํ• ๋‹นํ–ˆ์—ˆ๋‹ค. ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ left์™€ top ๊ฐ’์— ์ขŒํ‘œ๋ฅผ ์—ฐ๋™ํ•ด์ฃผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„๋œ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•ด์•ผ ํ•  ๊ฒƒ์€ ๊ฐ’์ด ์‚ฌ์šฉ๋  ๊ณณ์ด CSS์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์œ„ ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ๋ถ™์—ฌ์ค˜์•ผ ํ•œ๋‹ค.

zoomLens.style.left = x + 'px';
zoomLens.style.top = y + 'px';

์œ„์™€ ๊ฐ™์ด ๋งˆ์šฐ์Šค์˜ ์ขŒํ‘œ์™€ ์ด๋„ˆ ํ”„๋ ˆ์ž„ ์œ„์น˜์˜ ์˜์ ์ด ์—ฐ๋™๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งˆ์šฐ์Šค ์ปค์„œ๋Š” ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ค‘์•™์— ์œ„์น˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ๋„ˆ๋น„์™€ ๋†’์ด์˜ ์ ˆ๋ฐ˜์„ ๋ณด์ •๊ฐ’์œผ๋กœ ๋„ฃ์–ด์ค€๋‹ค.

zoomLens.style.left = x - 153 + 'px';
zoomLens.style.top = y - 117 + 'px';

๋งค์šฐ ์•„๋ฆ„๋‹ต๋‹ค. ์ด์ œ ๊ฐ’์ด ํ—ท๊ฐˆ๋ฆฌ์ง€ ์•Š๋„๋ก ๊ฐ์ฒด ์•ˆ์— ์ •๋ฆฌํ•˜๋ฉด ๋œ๋‹ค. ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋กœ ์–ธ์ œ๋“ ์ง€ ๊ฐ’์ด ํ•„์š”ํ• ๋•Œ๋งˆ๋‹ค ์ ‘๊ทผํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const coord = { x: x - 153 + 'px', y: y - 117 + 'px' }



[๋ช…์ œ 4] ์ด๋„ˆ ํ”„๋ ˆ์ž„์€ ์ด๋ฏธ์ง€ ์˜์—ญ ๊ฒฝ๊ณ„ ์•ˆ์—์„œ๋งŒ ์›€์ง์ธ๋‹ค.

๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ค‘ ๊ฐ€์žฅ ํ—ท๊ฐˆ๋ฆฌ๊ณ  ๊นŒ๋‹ค๋กœ์šด ๋ถ€๋ถ„์ด์—ˆ๋‹ค. ์ด๋„ˆ ํ”„๋ ˆ์ž„์ด ์™ธ๋ถ€ ํ”„๋ ˆ์ž„์„ ๊ฒฝ๊ณ„๋กœ ์ธ์‹ํ•˜๋Š” ๋ชจ์Šต์€ ์–ด๋–ป๊ฒŒ ๋กœ์ง์œผ๋กœ ํ’€์–ด๋‚ผ ์ˆ˜ ์žˆ์„๊นŒ? Figma๋กœ ํ•œ๋•€ ํ•œ๋•€ ๊ทธ๋ ค๊ฐ€๋ฉฐ ์˜์—ญ๋ณ„ ํ”ฝ์…€ ๊ฐ’์„ ๊ตฌํ•ด๋ดค๋‹ค.

์ปค์„œ๊ฐ€ ํŠน์ • ์˜์—ญ์— ์ง„์ž…ํ•˜๋ฉด ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์œ„์น˜ ๊ฐ’์€ ํŠน์ • ์ถ•์ด ๊ณ ์ • ๊ฐ’(Static) ๋˜๋Š” ๋ณ€๋™ ๊ฐ’(Dynamic)์œผ๋กœ ๋ณ€ํ™˜๋˜๋Š”์ง€์˜ ์—ฌ๋ถ€์— ํžŒํŠธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ์˜์—ญ๋ณ„ ์›€์ง์ž„์˜ ๋ณ€ํ™”๋Š” ์•„๋ž˜ ๋„ค ๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • X์ถ•๊ณผ Y์ถ•์ด ์ •์ ์ธ ์˜์—ญ
  • X์ถ•์ด ๋™์ , Y์ถ•์€ ์ •์ ์ธ ์˜์—ญ
  • X์ถ•์€ ์ •์ , Y์ถ•์€ ๋™์ ์ธ ์˜์—ญ
  • X์ถ•๊ณผ Y์ถ•์ด ๋™์ ์ธ ์˜์—ญ (Center)

๊ฒฐ๋ก ์ ์œผ๋กœ X์ถ•๊ณผ Y์ถ•์ด ๋™์ ์ธ Center ์˜์—ญ์˜ ๋„ค ๋ชจ์„œ๋ฆฌ ์ขŒํ‘œ๋ฅผ ๊ธฐ์ ์œผ๋กœ ๊ฐ’์˜ ์„ฑ์งˆ์ด ํŒ๊ฐ€๋ฆ„๋œ๋‹ค. ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ์ขŒํ‘œ๊ฐ€ ์–ด๋–ค ์˜์—ญ์— ์ง„์ž…ํ–ˆ๋Š”์ง€ ํŒ๋‹จํ•˜๋ ค๋ฉด ์˜์—ญ๋ณ„ ์กฐ๊ฑด๋ฌธ์„ ์ •๋ฆฌํ•ด์•ผํ•œ๋‹ค.

์ปค์„œ์˜ ์ขŒํ‘œ ๊ฐ’์„ ์˜์—ญ์˜ ์ขŒํ‘œ ๊ฐ’๊ณผ ๋น„๊ตํ•˜์—ฌ ํฌ๊ณ  ์ž‘์Œ์„ ๋”ฐ์ง€๋ฉด ์ปค์„œ๊ฐ€ ์–ด๋Š ์„นํ„ฐ์— ์ง„์ž…ํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๊ณ , ํ•ด๋‹น ์„นํ„ฐ์— ์ง„์ž…ํ–ˆ์„๋•Œ ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ๋ฅผ ๋™์ ์œผ๋กœ, ๋˜๋Š” ๊ณ ์ •๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋œ๋‹ค.

์ˆซ์ž๋ฅผ ๋‚จ๋ฐœํ•˜๊ฒŒ ๋˜๋ฉด ๋‚˜์ค‘์— ํ”„๋ ˆ์ž„์˜ ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์กŒ์„๋•Œ ์ˆ˜์ •ํ•˜๊ธฐ ๊ท€์ฐฎ๊ณ , ๋ˆ„๋ฝ ๋˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์›Œ์„œ ๋ณ€์ˆ˜๋กœ ์น˜ํ™˜ํ•ด์ฃผ๊ธฐ๋กœ ํ–ˆ๋‹ค. ์ฐธ์กฐํ•ด์•ผ ํ•  ๊ฒฝ๊ณ„์„ ์€ ์ด ๋„ค ๊ฐœ, x์˜ ์ตœ์†Œ๊ฐ’, ์ตœ๋Œ€๊ฐ’๊ณผ y์˜ ์ตœ์†Œ๊ฐ’ ์ตœ๋Œ€๊ฐ’์ด๋‹ค.

๊ฐ’์„ ๋ณ€์ˆ˜๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ์–ธ์ œ๋“ ์ง€ ์œ ๋™์ ์œผ๋กœ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ณ , ๋น„๊ต๋˜๋Š” ๊ฐ’์˜ ์˜๋ฏธ๋ฅผ ๋ช…ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ’๋“ค์€ ๊ฐ์ฒด์— ์ €์žฅํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์ง ํ•ด ๋ณด์ธ๋‹ค. ์˜๋ฏธ์™€ ๋ชฉ์ ์ด ๋น„์Šทํ•œ ๊ฒƒ๋“ค์€ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์—ฌ๋Ÿฌ๋ชจ๋กœ ๊น”๋”ํ•˜๊ณ  ๊ฐ„ํŽธํ•˜๋‹ค.

const boundary = { xMin: 153, xMax: 297, yMin: 117, yMax: 353 };

์ด์ œ ์œ„ ๋„์‹์„ ์ฐธ๊ณ ํ•˜์—ฌ ์กฐ๊ฑด๋ฌธ์„ ๋งŒ๋“ค์–ด ํ•ด๋‹น ์˜์—ญ์— ์ง„์ž…ํ–ˆ์Œ์„ ์ œ๋Œ€๋กœ ํ‘œํ˜„ํ•˜๋Š”์ง€ ์‹œํ—˜ํ•ด๋ณธ๋‹ค.

if (x <= boundary.xMin && y <= boundary.yMin) {
  console.log(5)
} else if (x > boundary.xMin && x < boundary.xMax && y <= boundary.yMin) {
  console.log(1)
} else if (x >= boundary.xMax && y <= boundary.yMin) {
  console.log(6)
} else if (x <= boundary.xMin && y > boundary.yMin && y < boundary.yMax) {
  console.log(3)
} else if (x <= boundary.xMin && y >= boundary.yMax) {
  console.log(7)
} else if (x > boundary.xMin && x < boundary.xMax && y >= boundary.yMax) {
  console.log(2)
} else if (x >= boundary.xMax && y >= boundary.yMax) {
  console.log(8)
} else if (x >= boundary.xMax && y > boundary.yMin && y < boundary.yMax) {
  console.log(4)
} else {
  console.log('center')
}

์œ„์™€ ๊ฐ™์ด ์ปค์„œ๊ฐ€ ์˜์—ญ์— ์ง„์ž…ํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์˜์—ญ์˜ ์ˆซ์ž๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. if..else ๋ฌธ์€ ๋„ˆ๋ฌด ๋ชป์ƒ๊ฒผ์œผ๋‹ˆ switch๋ฌธ์œผ๋กœ ๋ฐ”๊พธ๊ณ , ์ฝ˜์†” ๋Œ€์‹  ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ ๊ฐ’์„ ์กฐ๊ฑด์— ๋งž์ถฐ ๋ฐ”๊ฟ” ๋„ฃ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

switch (true) {

  case (x <= boundary.xMin && y <= boundary.yMin) :
    zoomLens.style.left = '0';
    zoomLens.style.top = '0';
    break;

  case (x > boundary.xMin && x < boundary.xMax && y <= boundary.yMin) :
    zoomLens.style.left = coord.x;
    zoomLens.style.top = '0';
    break;

  case (x >= boundary.xMax && y <= boundary.yMin) :
    zoomLens.style.left = '145px';
    zoomLens.style.top = '0';
    break;

  case (x <= boundary.xMin && y > boundary.yMin && y < boundary.yMax) :
    zoomLens.style.left = '0';
    zoomLens.style.top = coord.y;
    break;

  case (x <= boundary.xMin && y >= boundary.yMax) :
    zoomLens.style.left = '0';
    zoomLens.style.top = '236px';
    break;

  case (x > boundary.xMin && x < boundary.xMax && y >= boundary.yMax) :
    zoomLens.style.left = coord.x;
    zoomLens.style.top = '236px';
    break;

  case (x >= boundary.xMax && y >= boundary.yMax) :
    zoomLens.style.left = '145px';
    zoomLens.style.top = '236px';
    break;

  case (x >= boundary.xMax && y > boundary.yMin && y < boundary.yMax) :
    zoomLens.style.left = '145px';
    zoomLens.style.top = coord.y;
    break;

  default :
    zoomLens.style.left = coord.x;
    zoomLens.style.top = coord.y;
}

์ •์ ์ธ ๊ฐ’์€ ๊ณ ์ •๋œ ํ”ฝ์…€ ๊ฐ’์„ ๋„ฃ๊ณ , ๋™์ ์ธ ๊ฐ’์€ ์ขŒํ‘œ ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ฐ์ฒด coord์˜ ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ์ฐธ์กฐํ•œ๋‹ค. ์œ„ ์กฐ๊ฑด๋ฌธ์„ ๋„ฃ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์˜๋„ํ•œ ๋ฐ”๊ฐ€ ์‹คํ˜„๋˜๋Š” ์•„๋ฆ„๋‹ค์€ ๊ด‘๊ฒฝ์„ ๋ชฉ๊ฒฉํ•˜๊ฒŒ ๋œ๋‹ค.




[๋ช…์ œ 5] ํ™•๋Œ€ ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ ์ด๋„ˆ ํ”„๋ ˆ์ž„ ์˜์—ญ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์—ฌ์•ผ ํ•˜๋ฉฐ, ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ๋„ ์›€์ง์ž„์€ ๋™๊ธฐํ™”๋˜์–ด์•ผ ํ•œ๋‹ค.

ํ—ท๊ฐˆ๋ฆฌ์ง€๋งŒ ์•Š์œผ๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฏธ์ง€ ํ”„๋ ˆ์ž„๊ณผ ๊ด€๊ณ„๋œ ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ƒ๋Œ€์  ์œ„์น˜์™€ ํ™•๋Œ€ ๋ทฐํฌํŠธ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํฌ์ง€์…˜์„ ํผ์„ผํ…Œ์ด์ง€๋กœ ์—ฐ๋™ํ•˜๋ฉด ๋œ๋‹ค.

์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์œ„์น˜๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ•  ์ˆ˜ ์žˆ์„๊นŒ? ์ด ๊ฒƒ ๋˜ํ•œ ๋ฐ”๊นฅ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ ๊ฐ’๊ณผ (DOMRect)์™€ ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ ๊ฐ’์„ ์‚ฐ์ˆ ํ•˜๋ฉด ๊ธˆ๋ฐฉ ํ’€๋ฆฐ๋‹ค.

์™ธ๋ถ€ ํ”„๋ ˆ์ž„์ด getBoundingClientRect() ๋ฉ”์†Œ๋“œ๋กœ ๊ฐ์ฒด ํฌ๊ธฐ, ์œ„์น˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™”๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์ด๋„ˆ ํ”„๋ ˆ์ž„๋„ ๋˜‘๊ฐ™์ด ์ขŒํ‘œ๋ฅผ ๊ฐ€์ ธ์™€ ๋ถ„ํ•ด ํ• ๋‹นํ•œ๋‹ค.

const {left, top} = zoomFrame.getBoundingClientRect();
const {x:lensLeft, y:lensTop} = zoomLens.getBoundingClientRect();

๋ทฐํฌํŠธ ๋Œ€๋น„ ๋ฐ”๊นฅ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ๋ฅผ ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ขŒํ‘œ์—์„œ ๋นผ์ค€ ๊ฐ’์œผ๋กœ, ์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ ์ด๋™ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€๊ฐ’์„ ๋‚˜๋ˆ„์–ด ๋ฐฑ๋ถ„์œจ์„ ๊ตฌํ•˜๋ฉด ๋œ๋‹ค.

์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ x์ถ• ์œ„์น˜ ๋ฐฑ๋ถ„์œจ = (lensLeft - left) x 100 / 145
์ด๋„ˆ ํ”„๋ ˆ์ž„์˜ y์ถ• ์œ„์น˜ ๋ฐฑ๋ถ„์œจ = (lensTop - top) x 100 / 236

์ด ์ˆ˜์‹์„ CSS ํฌ์ง€์…˜ ๊ฐ’์œผ๋กœ ์ ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

zoomWindow.style.backgroundPosition =
`${(lensLeft - left) * 100 / 145}% ${(lensTop - top) * 100 / 236}%`

์•„๋ž˜์™€ ๊ฐ™์ด ๋งค์šฐ ์ž˜ ์ž‘๋™ํ•œ๋‹ค.




ํ›„๊ธฐ

์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์„ ๋ฏธ๋ จํ•˜๊ฒŒ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ดค๋‹ค. ๋™์ ์ธ ์›น์‚ฌ์ดํŠธ ๊ธฐ๋Šฅ์˜ ์›๋ฆฌ๋ฅผ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋˜ ์ข‹์€ ๊ณ„๊ธฐ์˜€๋‹ค.

๋‚ด๊ฐ€ ์ƒ๊ฐํ•œ ์ด๋ก ์ด ์‹ค์ œ๋กœ ๊ตฌํ˜„๋˜๋Š” ๋ชจ์Šต์ด ๋„ˆ๋ฌด ์ฆ๊ฑฐ์›Œ์„œ ๋ณด๋žŒ์ด ์žˆ์—ˆ๋‹ค.
์ด๋ฏธ์ง€ ์คŒ ๊ธฐ๋Šฅ์ด ํ• ๋ง์ด ์ œ์ผ ๋งŽ์•„์„œ ๋…๋ฆฝ๋œ ํฌ์ŠคํŠธ๋กœ ๋‚จ๊ธด๋‹ค.



๊ธ€๊ณผ ๊ทธ๋ฆผ โ“’ Wonkook Lee
์ฐธ๊ณ ํ•œ ํ•ด๋‹น ํ™ˆํŽ˜์ด์ง€์˜ ๋ฆฌ์†Œ์Šค์™€ ์Œ๋ฃŒ ์‚ฌ์ง„์˜ ๋ชจ๋“  ์ €์ž‘๊ถŒ์€
์Šคํƒ€๋ฒ…์Šค ์ฝ”๋ฆฌ์•„์—๊ฒŒ ์žˆ์œผ๋ฉฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์‹œ ์ฆ‰์‹œ ์กฐ์น˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ™๐Ÿป ์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด ์ง€์ ํ•ด์ฃผ์„ธ์š”

profile
ยฉ ๊ฐ€์น˜ ์ง€ํ–ฅ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž

2๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2021๋…„ 8์›” 28์ผ

ํฅ๋ฏธ๋กœ์šด ๋‚ด์šฉ์ด๋„ค์š” ์ž˜๋ดค์Šต๋‹ˆ๋‹ค :)

1๊ฐœ์˜ ๋‹ต๊ธ€