JavaScript
[JavaScript] hammer.js로 갤러리 이미지 확대/축소하기
Shonir00ng
2023. 3. 8. 16:01
프로젝트에 이미 lightbox 플러그인이 적용된 상태였는데 이미지 확대/축소 기능 추가 요청이 들어왔다.
다른 플러그인으로 바꿀 자신이 없어 Hammer.js를 사용해 어찌저찌 기능을 추가했다...😢
[목표]
- 두 손가락으로 이미지 줌(확대/축소)가 가능할 것
- 확대 후 pan을 이용해 두 손가락으로 이미지 탐색이 가능할 것
- 원래 이미지 크기보다 축소되지 않을 것
- swipe 시 이미지가 움직이지 않고 이동 될 것
Hammer.js 홈페이지 메인에 있는 스크립트를 긁어 참조했다.
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;
}