缩放 > 1 时 Touchmove 捏合缩放跳跃位置

问题描述 投票:0回答:1

我正在尝试对图像实现捏缩放。

捏缩放第一次似乎没问题 - 当缩放〜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>

如何才能获得更流畅的体验?

javascript html
1个回答
0
投票

因此,没有更好的选择 - 我已经切换到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>

© www.soinside.com 2019 - 2024. All rights reserved.