JavaScript

[JavaScript] hammer.js로 갤러리 이미지 확대/축소하기

Shonir00ng 2023. 3. 8. 16:01

프로젝트에 이미 lightbox 플러그인이 적용된 상태였는데 이미지 확대/축소 기능 추가 요청이 들어왔다.

다른 플러그인으로 바꿀 자신이 없어 Hammer.js를 사용해 어찌저찌 기능을 추가했다...😢

 

 

[목표]

  • 두 손가락으로 이미지 줌(확대/축소)가 가능할 것
  • 확대 후 pan을 이용해 두 손가락으로 이미지 탐색이 가능할 것
  • 원래 이미지 크기보다 축소되지 않을 것
  • swipe 시 이미지가 움직이지 않고 이동 될 것

 

Hammer.js 홈페이지 메인에 있는 스크립트를 긁어 참조했다.

http://hammerjs.github.io/

 

Hammer.JS - Hammer.js

 

hammerjs.github.io

 

이벤트를 적용할 이미지는 반드시 css에서 touch-action none으로 지정하자.

안그럼 pinch 할 때 이미지 위치가 이상해짐.

var screen;			// 이미지
var el;
var img;
var imageX;
var imageY;
var currentX;
var currentY;
var initScale;
var transform = [];

// 갤러리에서 썸네일 클릭시
$('.btn-pic').on('click', function() {
	// 이미지 띄우기
    var url = $(this).data('pic-url');
    $(this).find('img').attr('data-src', url);		

    /* ------------------------------------------ hammer.js */

    screen = document.querySelector(".lb-lightbox");	// 뭔지 몰라서 image-container 바깥 클래스로 지정함
    el = document.querySelector('.image-container');	// bootstrap.min.js에서 추가한 image 밖 div 클래스
    img = document.querySelector('.lb-image');
    var mc = new Hammer.Manager(el);

    imageX = Math.round((screen.offsetWidth - el.offsetWidth) / 2);
    imageY = Math.round((screen.offsetHeight - el.offsetHeight) / 2);

    mc.add(new Hammer.Pan({ threshold: 0, pointers: 2}));	
    mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith(mc.get('pan'));

    mc.on("panstart panmove", onPan);
    mc.on("pinchstart pinchmove", onPinch);
    mc.on("panend pancancel", onEnd);

    /* ------------------------------------------ hammer.js */

})

// 두 손가락을 벌리거나 오므릴 때 화면 확대/축소
function onPinch(ev) {
    if(ev.type == 'pinchstart') {
        initScale = transform.scale || 1;
    }
    // 원래 이미지보다 축소 못하게 하기
    if(initScale * ev.scale > 1) {	    	
        transform.scale = initScale * ev.scale;
    } else {
        transform.scale = 1;
    }

    elementUpdate();
}

// 확대 후 드래그로 이미지 탐색을 위한 pan 이벤트
function onPan(ev) {
    currentX = imageX + ev.deltaX
	currentY = imageY + ev.deltaY
    transform.translate = {
        x: startX + ev.deltaX,
        y: startY + ev.deltaY
    };
    elementUpdate();
}

// pan 끝났을 때 이벤트
function onEnd(ev) {		

	// 이미지 탐색 범위가 되는 최소좌표, 최대좌표 구하기
    minRangeX = 0 - (img.width * ev.scale / 2);
    minRangeY = 0 - (img.height * ev.scale / 2);		
    maxRangeX = img.width * ev.scale / 2;
    maxRangeY = img.height * ev.scale / 2;	
	
    // x좌표가 범위 벗어남
    if(currentX >= minRangeX && currentX <= maxRangeX) {
        imageX = currentX;
    } else if (currentX <= minRangeX) {
        imageX = minRangeX;
    } else {
        imageX = maxRangeX;
    }
    
	// y좌표가 범위 벗어남
    if(currentY >= minRangeY && currentY <= maxRangeY) {
        imageY = currentY;
    } else if (currentY <= minRangeY) {
        imageY = minRangeY;
    } else {
        imageY = maxRangeY;
    }

    $('.lb-number').text('imageX : ' + imageX + ', imageY : ' + imageY);

    elementUpdate();
}

function elementUpdate() {
	// 이미지 크기가 원본보다 작으면 좌표 이동 안됨
	if(transform.scale <= 1) {
        transform.translate = {
            x: 0,
            y: 0
        };
    }
    var value = [
        'translate3d(' + transform.translate.x + 'px, ' + transform.translate.y + 'px, 0)',
        'scale(' + transform.scale + ', ' + transform.scale + ')'
    ];	   

    value = value.join(" ");
    el.style.webkitTransform = value;
    el.style.mozTransform = value;
    el.style.transform = value;
}

/*
 * 이미지 닫거나 옆으로 넘기면 이전 이미지의 위치, 확대 정보가 유지되어 나오므로 초기화하기
 * 이미지 닫을 때 이벤트가 발생 확인이 도저히 안되는 관계로
 * bootstrap.min.js, custom.js의 닫기, swipe 이벤트에서 initImgPos를 호출하게함ㅠ
 */
function initImgPos() {
    var value =  'translate3d(0px, 0px, 0) scale(1, 1)';		
		
    el.style.webkitTransform = value;
    el.style.mozTransform = value;
    el.style.transform = value;
}