본문 바로가기

Publishing

자바스크립트 돋보기 기능 구현 2

Javascript/jQuery 돋보기 2


지난 포스팅에서 마우스 위치에 따라 사진을 확대하는 기능을 만들어 보았는데, 이번 포스팅에서는 아래 사진과 같이 진짜 돋보기라고 할 만한 것을 구현해보고자 합니다.


HTML

저번 포스팅과 구조는 동일한데 <div><img>태그로 바꿨습니다.

1
2
3
<div class="wrap">
    <img class="target" src="https://i.imgur.com/zEZCgJC.jpg" />
</div>
cs

CSS

별건 없고.. 지난 포스팅에서 돋보기가 추가되었습니다.

저번 포스팅처럼 HTML 에는 없지만 자바스크립트로 추가될 거에요. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
/* 감싸는 div */
.wrap {
    position: relative;
    width: 500px;
    height: 500px;
    margin: 0 auto;
}
/* 확대될 타겟이미지*/
.target {
    display: block;
    width: 100%;
}
/* 돋보기 */
.magnifier {
    width: 100px;
    height: 100px;
    position: absolute;
    border-radius: 100%;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.85), 0 0 3px 3px rgba(0, 0, 0, 0.25);
    display: none;
}
cs

JS

이 부분도 저번 포스팅과 비슷합니다.
돋보기 역할의 div.magnifier를 자식요소로 추가하고 img.target의 이미지를 복사해 줍니다.
1
2
3
4
5
6
7
8
9
$(".wrap")
    .on('mousemove', magnify)
    .prepend("<div class='magnifier'></div>")
    .children('.magnifier').css({
        "background""url('" + $(".target").attr("src"+ "') no-repeat"
    });
 
var target = $('.target');
var magnifier = $('.magnifier');
cs


그리고 바인딩한 function은 아래와 같습니다.

주석에 달린 번호와 함께 아래 설명을 봐주시기 바랍니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function magnify(e) {
 
    // 1
    var mouseX = e.pageX - $(this).offset().left;
    var mouseY = e.pageY - $(this).offset().top;
 
    // 2
    if (mouseX < $(this).width() && mouseY < $(this).height() && mouseX > 0 && mouseY > 0) {
        magnifier.fadeIn(100);
    } else {
        magnifier.fadeOut(100);
    }
 
    // 3
    if (magnifier.is(":visible")) {
 
        // 4    
        var rx = -(mouseX / target.width() * target[0].naturalWidth - magnifier.width() / 2);
        var ry = -(mouseY / target.height() * target[0].naturalHeight - magnifier.height()  /2);
 
        // 5
        var px = mouseX - magnifier.width() / 2;
        var py = mouseY - magnifier.height() / 2;
 
        // 6
        magnifier.css({
            left: px,
            top: py,
            backgroundPosition: rx + "px " + ry + "px"
        });
    }
}
cs


  1. 저번 포스팅과 같이, 실제 마우스 좌표에서 컨테이너(div.wrapoffset 위치를 차감해 컨테이너 안쪽에서의 마우스 좌표를 얻습니다. 현재 컨테이너를 500px로 고정해놨으니 왼쪽상단 모서리가 (0 , 0), 오른쪽상단 모서리가 (500, 0) 이 됩니다.
  2. 컨테이너 안에 마우스가 있으면 div.magnifier를 드러나게 하고, 벗어나면 감춥니다.
  3. div.magnifier가 드러나 있으면
  4. img.target 위에 위치한 마우스 위치를 기준으로 하여 본래 이미지 크기에 대한 마우스 좌표를 얻습니다.
  5. div.magnifier를 마우스 가운데 위치시키기 위해 width, height 절반을 차감시킵니다.
  6. 적용합니다.
아마 다른건 곧바로 이해할 수 있는데 4번은 대충 보기엔 뭔말인가 싶을 겁니다.
이해를 쉽게 하려면 확대하는 방식에 대해 먼저 이해해야 합니다. 

지난 포스팅에서는 
확대기능을 위해 추가한 자식요소가 원본과 완벽히 같은 위치에, 같은 사진을 갖고 겹쳐져 있었습니다. 
그 복사본을 단지 scale()로 확대하고 transform-origin으로 마우스를 따라다니게 만들었을 뿐입니다.

그러나 이번 포스팅에서는 이미지를 복사하되 마우스를 갖다댄 부분을 제외하면 원본은 뒤에 그대로 남아있어야 합니다.
다시금 아래 사진을 봅시다.

현재 css에 돋보기 크기를 150px로 설정해 놓았으므로 150x150을 제외한 나머지 부분은 그대로 보여져야 해요.

그래서 이번 포스팅에 쓰인 방식은 브라우저에 보여지는 축소된 이미지 위에 마우스를 올리면, 
원본 이미지에서의 좌표를 계산해서 해당 위치의 원본을 돋보기 모양 안에 보여주는 것입니다. 

그걸 구현하기 위한 것이 6번에서 쓰인 background-position이며 4번은 그 위치를 잡기 위한 계산입니다. 

다시 한 번 계산식을 볼까요.
1
2
var rx = -(mouseX / target.width() * target[0].naturalWidth - magnifier.width() / 2);
var ry = -(mouseY / target.height() * target[0].naturalHeight - magnifier.height() / 2);
cs

mouseX는 지난 포스팅에서 설명했듯 현재 컨테이너에 대한 마우스 좌표값입니다. 

target.width()는 현재 확대하려고 하는 타겟이미지의 너비입니다. (현재 500px 고정)

target[0].naturalWidth는 원본이미지의 너비를 구하는 것입니다. 대충 계산하기 쉽게 2000px 이라고 가정해 볼게요.

  1. 그럼 내가 500x500 사진 한가운데 마우스를 올려놓고 있다면 
  2. mouseX, mouseY(250, 250)이 됩니다. 
  3. 250을 타겟이미지의 너비/높이인 500으로 나눠 0.5를 얻습니다.
  4. 거기에 원본이미지의 너비/높이인 2000을 곱하면 
  5. 원본이미지의 한가운데 마우스 좌표인 (1000, 1000)을 얻게 됩니다.

그러나 이대로 적용한다면 돋보기 div.magnifier가 마우스 우측하단부터 자리하게 되므로 마우스 한가운데 위치시키기 위해 돋보기 너비,높이의 절반을 각각 빼주는 것입니다.

결과

아름다운 돋보기가 완성되었습니다!


주의

이 코드는 이미지를 x배의 배율로 확대해 보여주는 것이 아니라 마우스를 갖다 대면 원본크기 이미지를 위치에 맞게 겹쳐서 보여주는 꼼수입니다.

따라서 원본이미지를 100% 크기로 사용하면 아무런 효과가 없고,
원본이미지보다 오히려 확대해서 브라우저에 보여지고 있다면 돋보기가 아니라 오히려 축소경이 됩니다. 

어설픈 것 같지만 포스팅하면서 찾아보니 의외로 이런 방식으로 구현해놓은 라이브러리가 꽤 있더라구요. 
img 태그에 원본이미지와 축소이미지 url을 둘 다 넣으라는 라이브러리도 있구요. 

하지만 여기서 아주 약간만 고치면 zoom 배율을 설정하는 진짜 방식으로 고칠 수 있는데, 그건 다음 포스팅에 이어집니다. 

참고

포스팅에 사용한 전체 코드 : https://github.com/SaintSilver/Magnifying-Glass