我正在尝试对图像实现捏缩放。
捏缩放第一次似乎没问题 - 当缩放〜1时 - 但是当我缩放图像以放大某个点时,松开然后尝试放大新点(并且从已经缩放的图像)然后新的触摸似乎使图像跳跃。
看到这一点的最佳方法是运行示例代码并尝试最大程度地放大眼睛,然后放开,然后再次尝试进一步放大眼睛。
var _img = document.querySelector('img');
var _container = document.querySelector('#container');
var _pinching = false;
var _initialDistance=0, _initialScale=1, _initialTranslateX=0, _initialTranslateY=0, _translateX=0, _translateY=0;
_container.addEventListener('touchstart', (event) => {
console.log('touchstart '+event.touches.length);
event.preventDefault();
if (event.touches.length === 2) {
const touch1 = event.touches[0];
const touch2 = event.touches[1];
_initialDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
_initialScale = parseFloat(_img.style.transform.match(/scale\(([^)]+)\)/)?.[1]) || 1;
_initialTranslateX = _translateX * _initialScale;
_initialTranslateY = _translateY * _initialScale;
_initialCenterX = (touch1.clientX + touch2.clientX) / 2 / _initialScale;
_initialCenterY = (touch1.clientY + touch2.clientY) / 2 / _initialScale;
console.log('touchstart pinching '+_initialCenterX+' / '+_initialCenterY);
_pinching = true;
}
});
document.addEventListener('touchmove', (event) => {
console.log('touchmove '+event.touches.length);
if (_pinching && event.touches.length === 2) {
const touch1 = event.touches[0];
const touch2 = event.touches[1];
const distance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY);
const scaleFactor = distance / _initialDistance;
// Calculate the center point between the two touches
const centerX = (touch1.clientX + touch2.clientX ) / 2 - _container.getBoundingClientRect().x;
const centerY = (touch1.clientY + touch2.clientY ) / 2 - _container.getBoundingClientRect().y;
// Apply transformations
const deltaX = centerX - _initialCenterX;
const deltaY = centerY - _initialCenterY;
let translateX = _initialTranslateX + deltaX * scaleFactor;
let translateY = _initialTranslateY + deltaY * scaleFactor;
let scaleAmount = _initialScale * scaleFactor;
console.log(`sa=${scaleAmount} / itx=${_initialTranslateX} / dx=${deltaX} / ity=${_initialTranslateY} / dy=${deltaY} / is=${_initialScale} / sf=${scaleFactor} / sa=${scaleAmount}`);
if ( scaleAmount <= 1) {
scaleAmount = 1;
translateX = 0;
translateY = 0;
}
const trans = parseInt(translateX) + 'px, ' + parseInt(translateY) + 'px';
_img.style.transform = `translate(${trans}) scale(${scaleAmount})`;
}
});
document.addEventListener('touchend', () => {
console.log('touchend ');
_pinching = false;
});
#container {
width: 100%;
overflow: hidden;
border:solid 1px grey;
}
img {
max-height: 100vh;
max-width: 400px;
-webkit-transition: all 0.05s ease-out;
-moz-transition: all 0.05s ease-out;
-ms-transition: all 0.05s ease-out;
transition: all 0.05s ease-out;
}
<div id='container'>
<img src='https://i.pinimg.com/originals/f3/40/bf/f340bf0e86d65b5aaa709a0e98eae829.jpg'>
</div>
如何才能获得更流畅的体验?
因此,没有更好的选择 - 我已经切换到hammer.js并重写了javascript(基于https://codepen.io/josephmaynard/pen/OjWvNP上找到的东西)-它并不完美,但更好。
let _windowresizeDone=false;
setImgHandlers(document.querySelector('img'));
function setImgHandlers(img) {
const imageContainer = img.parentElement;
let minScale = 1;
let maxScale = 40;
let imageWidth;
let imageHeight;
let containerWidth;
let containerHeight;
let displayImageX = 0;
let displayImageY = 0;
let displayImageScale = 1;
let displayDefaultWidth;
let displayDefaultHeight;
let rangeX = 0;
let rangeMaxX = 0;
let rangeMinX = 0;
let rangeY = 0;
let rangeMaxY = 0;
let rangeMinY = 0;
let displayImageRangeY = 0;
let displayImageCurrentX = 0;
let displayImageCurrentY = 0;
let displayImageCurrentScale = 1;
function resizeContainer() {
containerWidth = imageContainer.offsetWidth;
containerHeight = imageContainer.offsetHeight;
if (displayDefaultWidth !== undefined && displayDefaultHeight !== undefined) {
displayDefaultWidth = displayImage.offsetWidth;
displayDefaultHeight = displayImage.offsetHeight;
updateRange();
displayImageCurrentX = clamp(displayImageX, rangeMinX, rangeMaxX);
displayImageCurrentY = clamp(displayImageY, rangeMinY, rangeMaxY);
updateDisplayImage(
displayImageCurrentX,
displayImageCurrentY,
displayImageCurrentScale);
}
}
resizeContainer();
function clamp(value, min, max) {
return Math.min(Math.max(min, value), max);
}
function clampScale(newScale) {
return clamp(newScale, minScale, maxScale);
}
if ( !_windowresizeDone ) {
_windowresizeDone = true;
window.addEventListener('resize', resizeContainer, true);
}
const displayImage = img;
displayImage.onload = function () {
imageWidth = displayImage.width;
imageHeight = displayImage.height;
displayImage.addEventListener('mousedown', e => e.preventDefault(), false);
displayDefaultWidth = displayImage.offsetWidth;
displayDefaultHeight = displayImage.offsetHeight;
rangeX = Math.max(0, displayDefaultWidth - containerWidth);
rangeY = Math.max(0, displayDefaultHeight - containerHeight);
}
imageContainer.addEventListener('wheel', e => {
displayImageScale = displayImageCurrentScale = clampScale(displayImageScale + (e.wheelDelta / 800));
updateRange();
displayImageCurrentX = clamp(displayImageCurrentX, rangeMinX, rangeMaxX)
displayImageCurrentY = clamp(displayImageCurrentY, rangeMinY, rangeMaxY)
updateDisplayImage(displayImageCurrentX, displayImageCurrentY, displayImageScale);
}, false);
function updateDisplayImage(x, y, scale) {
const transform = 'translateX(' + x + 'px) translateY(' + y + 'px) translateZ(0px) scale(' + scale + ',' + scale + ')';
displayImage.style.transform = transform;
displayImage.style.WebkitTransform = transform;
displayImage.style.msTransform = transform;
}
function updateRange() {
rangeX = Math.max(0, Math.round(displayDefaultWidth * displayImageCurrentScale) - containerWidth);
rangeY = Math.max(0, Math.round(displayDefaultHeight * displayImageCurrentScale) - containerHeight);
rangeMaxX = Math.round(rangeX / 2);
rangeMinX = 0 - rangeMaxX;
rangeMaxY = Math.round(rangeY / 2);
rangeMinY = 0 - rangeMaxY;
}
const hammertime = new Hammer(imageContainer);
hammertime.get('pinch').set({enable: true});
hammertime.get('pan').set({direction: Hammer.DIRECTION_ALL});
hammertime.on('pan', ev => {
displayImageCurrentX = clamp(displayImageX + ev.deltaX, rangeMinX, rangeMaxX);
displayImageCurrentY = clamp(displayImageY + ev.deltaY, rangeMinY, rangeMaxY);
updateDisplayImage(displayImageCurrentX, displayImageCurrentY, displayImageScale);
});
hammertime.on('pinch pinchmove', ev => {
displayImageCurrentScale = clampScale(ev.scale * displayImageScale);
updateRange();
displayImageCurrentX = clamp(displayImageX + ev.deltaX, rangeMinX, rangeMaxX);
displayImageCurrentY = clamp(displayImageY + ev.deltaY, rangeMinY, rangeMaxY);
updateDisplayImage(displayImageCurrentX, displayImageCurrentY, displayImageCurrentScale);
});
hammertime.on('panend pancancel pinchend pinchcancel', () => {
displayImageScale = displayImageCurrentScale;
displayImageX = displayImageCurrentX;
displayImageY = displayImageCurrentY;
});
}
#container {
width: 100%;
overflow: hidden;
border:solid 1px grey;
}
img {
max-height: 100vh;
max-width: 400px;
-webkit-transition: all 0.05s ease-out;
-moz-transition: all 0.05s ease-out;
-ms-transition: all 0.05s ease-out;
transition: all 0.05s ease-out;
}
<script src='https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js'></script>
<div id='container'>
<img src='https://i.pinimg.com/originals/f3/40/bf/f340bf0e86d65b5aaa709a0e98eae829.jpg'>
</div>