programing

핀치를 감지하는 가장 간단한 방법

muds 2023. 8. 14. 23:09
반응형

핀치를 감지하는 가장 간단한 방법

이것은 기본 앱이 아닌 WEB 앱입니다.목표-CNS 명령을 사용하지 마십시오.

그래서 iOS에서 '핀치' 이벤트를 감지해야 합니다.문제는 제스처 또는 멀티 터치 이벤트를 수행할 때 나타나는 모든 플러그인 또는 방법이 (일반적으로) jQuery와 함께 있으며 태양 아래의 모든 제스처에 대한 전체 추가 플러그인이라는 것입니다.제 애플리케이션은 매우 크고, 저는 제 코드의 데드우드에 매우 민감합니다.제가 필요한 것은 핀치를 감지하는 것이고, jGesture와 같은 것을 사용하는 것은 제 단순한 필요에 비해 비대해지는 방법입니다.

또한 수동으로 핀치를 감지하는 방법에 대한 이해가 부족합니다.양쪽 손가락의 위치를 파악할 수 있습니다. 혼합물을 제대로 감지할 수 없는 것 같습니다.핀치를 감지하는 간단한 스니펫을 가진 사람이 있습니까?

생각해 보세요.pinch이벤트: 요소의 두 손가락이 서로를 향하거나 멀어지는 것입니다.제스처 이벤트는 상당히 새로운 표준이므로 다음과 같은 터치 이벤트를 사용하는 것이 가장 안전할 것입니다.

(ontouchstart이벤트)

if (e.touches.length === 2) {
    scaling = true;
    pinchStart(e);
}

(ontouchmove이벤트)

if (scaling) {
    pinchMove(e);
}

(ontouchend이벤트)

if (scaling) {
    pinchEnd(e);
    scaling = false;
}

두 손가락 사이의 거리를 구하려면,hypot함수:

var dist = Math.hypot(
    e.touches[0].pageX - e.touches[1].pageX,
    e.touches[0].pageY - e.touches[1].pageY);

, 이벤트를 사용하려고 합니다.두 개 이상의 손가락이 화면에 닿을 때마다 트리거됩니다.

핀치 제스처를 사용하여 수행해야 하는 작업에 따라 접근 방식을 조정해야 합니다.scale승수를 검사하여 사용자의 핀치 제스처가 얼마나 극적이었는지 확인할 수 있습니다.자세한 내용은 Apple의 TouchEvent 설명서를 참조하십시오.scale속성이 동작합니다.

node.addEventListener('gestureend', function(e) {
    if (e.scale < 1.0) {
        // User moved fingers closer together
    } else if (e.scale > 1.0) {
        // User moved fingers further apart
    }
}, false);

당신은 또한 그것을 가로챌 수 있습니다.gesturechange앱의 반응성을 높이기 위해 필요한 경우 발생하는 핀치를 감지하는 이벤트입니다.

해머.js 끝까지!변환(핀치)을 처리합니다.http://eightmedia.github.com/hammer.js/

하지만 당신이 직접 실행하기를 원한다면, 제프리의 대답은 꽤 확실하다고 생각합니다.

불행하게도, 브라우저에서 핀치 제스처를 감지하는 것은 사람들이 희망하는 것만큼 간단하지 않지만, HammerJS는 그것을 훨씬 더 쉽게 만듭니다!

HammerJS를 사용한 핀치 줌 및 팬 데모를 확인하십시오.이 예제는 Android, iOS 및 Windows Phone에서 테스트되었습니다.

소스 코드는 HammerJS를 사용한 핀치 줌 및에서 찾을 수 있습니다.

사용자의 편의를 위해 소스 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport"
        content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
  <title>Pinch Zoom</title>
</head>

<body>

  <div>

    <div style="height:150px;background-color:#eeeeee">
      Ignore this area. Space is needed to test on the iPhone simulator as pinch simulation on the
      iPhone simulator requires the target to be near the middle of the screen and we only respect
      touch events in the image area. This space is not needed in production.
    </div>

    <style>

      .pinch-zoom-container {
        overflow: hidden;
        height: 300px;
      }

      .pinch-zoom-image {
        width: 100%;
      }

    </style>

    <script src="https://hammerjs.github.io/dist/hammer.js"></script>

    <script>

      var MIN_SCALE = 1; // 1=scaling when first loaded
      var MAX_SCALE = 64;

      // HammerJS fires "pinch" and "pan" events that are cumulative in nature and not
      // deltas. Therefore, we need to store the "last" values of scale, x and y so that we can
      // adjust the UI accordingly. It isn't until the "pinchend" and "panend" events are received
      // that we can set the "last" values.

      // Our "raw" coordinates are not scaled. This allows us to only have to modify our stored
      // coordinates when the UI is updated. It also simplifies our calculations as these
      // coordinates are without respect to the current scale.

      var imgWidth = null;
      var imgHeight = null;
      var viewportWidth = null;
      var viewportHeight = null;
      var scale = null;
      var lastScale = null;
      var container = null;
      var img = null;
      var x = 0;
      var lastX = 0;
      var y = 0;
      var lastY = 0;
      var pinchCenter = null;

      // We need to disable the following event handlers so that the browser doesn't try to
      // automatically handle our image drag gestures.
      var disableImgEventHandlers = function () {
        var events = ['onclick', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover',
                      'onmouseup', 'ondblclick', 'onfocus', 'onblur'];

        events.forEach(function (event) {
          img[event] = function () {
            return false;
          };
        });
      };

      // Traverse the DOM to calculate the absolute position of an element
      var absolutePosition = function (el) {
        var x = 0,
          y = 0;

        while (el !== null) {
          x += el.offsetLeft;
          y += el.offsetTop;
          el = el.offsetParent;
        }

        return { x: x, y: y };
      };

      var restrictScale = function (scale) {
        if (scale < MIN_SCALE) {
          scale = MIN_SCALE;
        } else if (scale > MAX_SCALE) {
          scale = MAX_SCALE;
        }
        return scale;
      };

      var restrictRawPos = function (pos, viewportDim, imgDim) {
        if (pos < viewportDim/scale - imgDim) { // too far left/up?
          pos = viewportDim/scale - imgDim;
        } else if (pos > 0) { // too far right/down?
          pos = 0;
        }
        return pos;
      };

      var updateLastPos = function (deltaX, deltaY) {
        lastX = x;
        lastY = y;
      };

      var translate = function (deltaX, deltaY) {
        // We restrict to the min of the viewport width/height or current width/height as the
        // current width/height may be smaller than the viewport width/height

        var newX = restrictRawPos(lastX + deltaX/scale,
                                  Math.min(viewportWidth, curWidth), imgWidth);
        x = newX;
        img.style.marginLeft = Math.ceil(newX*scale) + 'px';

        var newY = restrictRawPos(lastY + deltaY/scale,
                                  Math.min(viewportHeight, curHeight), imgHeight);
        y = newY;
        img.style.marginTop = Math.ceil(newY*scale) + 'px';
      };

      var zoom = function (scaleBy) {
        scale = restrictScale(lastScale*scaleBy);

        curWidth = imgWidth*scale;
        curHeight = imgHeight*scale;

        img.style.width = Math.ceil(curWidth) + 'px';
        img.style.height = Math.ceil(curHeight) + 'px';

        // Adjust margins to make sure that we aren't out of bounds
        translate(0, 0);
      };

      var rawCenter = function (e) {
        var pos = absolutePosition(container);

        // We need to account for the scroll position
        var scrollLeft = window.pageXOffset ? window.pageXOffset : document.body.scrollLeft;
        var scrollTop = window.pageYOffset ? window.pageYOffset : document.body.scrollTop;

        var zoomX = -x + (e.center.x - pos.x + scrollLeft)/scale;
        var zoomY = -y + (e.center.y - pos.y + scrollTop)/scale;

        return { x: zoomX, y: zoomY };
      };

      var updateLastScale = function () {
        lastScale = scale;
      };

      var zoomAround = function (scaleBy, rawZoomX, rawZoomY, doNotUpdateLast) {
        // Zoom
        zoom(scaleBy);

        // New raw center of viewport
        var rawCenterX = -x + Math.min(viewportWidth, curWidth)/2/scale;
        var rawCenterY = -y + Math.min(viewportHeight, curHeight)/2/scale;

        // Delta
        var deltaX = (rawCenterX - rawZoomX)*scale;
        var deltaY = (rawCenterY - rawZoomY)*scale;

        // Translate back to zoom center
        translate(deltaX, deltaY);

        if (!doNotUpdateLast) {
          updateLastScale();
          updateLastPos();
        }
      };

      var zoomCenter = function (scaleBy) {
        // Center of viewport
        var zoomX = -x + Math.min(viewportWidth, curWidth)/2/scale;
        var zoomY = -y + Math.min(viewportHeight, curHeight)/2/scale;

        zoomAround(scaleBy, zoomX, zoomY);
      };

      var zoomIn = function () {
        zoomCenter(2);
      };

      var zoomOut = function () {
        zoomCenter(1/2);
      };

      var onLoad = function () {

        img = document.getElementById('pinch-zoom-image-id');
        container = img.parentElement;

        disableImgEventHandlers();

        imgWidth = img.width;
        imgHeight = img.height;
        viewportWidth = img.offsetWidth;
        scale = viewportWidth/imgWidth;
        lastScale = scale;
        viewportHeight = img.parentElement.offsetHeight;
        curWidth = imgWidth*scale;
        curHeight = imgHeight*scale;

        var hammer = new Hammer(container, {
          domEvents: true
        });

        hammer.get('pinch').set({
          enable: true
        });

        hammer.on('pan', function (e) {
          translate(e.deltaX, e.deltaY);
        });

        hammer.on('panend', function (e) {
          updateLastPos();
        });

        hammer.on('pinch', function (e) {

          // We only calculate the pinch center on the first pinch event as we want the center to
          // stay consistent during the entire pinch
          if (pinchCenter === null) {
            pinchCenter = rawCenter(e);
            var offsetX = pinchCenter.x*scale - (-x*scale + Math.min(viewportWidth, curWidth)/2);
            var offsetY = pinchCenter.y*scale - (-y*scale + Math.min(viewportHeight, curHeight)/2);
            pinchCenterOffset = { x: offsetX, y: offsetY };
          }

          // When the user pinch zooms, she/he expects the pinch center to remain in the same
          // relative location of the screen. To achieve this, the raw zoom center is calculated by
          // first storing the pinch center and the scaled offset to the current center of the
          // image. The new scale is then used to calculate the zoom center. This has the effect of
          // actually translating the zoom center on each pinch zoom event.
          var newScale = restrictScale(scale*e.scale);
          var zoomX = pinchCenter.x*newScale - pinchCenterOffset.x;
          var zoomY = pinchCenter.y*newScale - pinchCenterOffset.y;
          var zoomCenter = { x: zoomX/newScale, y: zoomY/newScale };

          zoomAround(e.scale, zoomCenter.x, zoomCenter.y, true);
        });

        hammer.on('pinchend', function (e) {
          updateLastScale();
          updateLastPos();
          pinchCenter = null;
        });

        hammer.on('doubletap', function (e) {
          var c = rawCenter(e);
          zoomAround(2, c.x, c.y);
        });

      };

    </script>

    <button onclick="zoomIn()">Zoom In</button>
    <button onclick="zoomOut()">Zoom Out</button>

    <div class="pinch-zoom-container">
      <img id="pinch-zoom-image-id" class="pinch-zoom-image" onload="onLoad()"
           src="https://hammerjs.github.io/assets/img/pano-1.jpg">
    </div>


  </div>

</body>
</html>

Hammer.js와 같은 타사 립을 사용하여 쉽고 번거롭지 않게 손가락 두 개로 모든 요소를 핀치 줌할 수 있습니다(해머는 스크롤에 문제가 있습니다!).

function onScale(el, callback) {
    let hypo = undefined;

    el.addEventListener('touchmove', function(event) {
        if (event.targetTouches.length === 2) {
            let hypo1 = Math.hypot((event.targetTouches[0].pageX - event.targetTouches[1].pageX),
                (event.targetTouches[0].pageY - event.targetTouches[1].pageY));
            if (hypo === undefined) {
                hypo = hypo1;
            }
            callback(hypo1/hypo);
        }
    }, false);


    el.addEventListener('touchend', function(event) {
        hypo = undefined;
    }, false);
}

가장 간단한 방법은 '휠' 이벤트에 응답하는 것입니다.

은 야합다니화에 .ev.preventDefault()브라우저가 전체 화면 확대/축소를 수행하지 못하도록 합니다.

브라우저는 트랙패드의 핀치에 대해 '휠' 이벤트를 합성하며, 보너스로 마우스 휠 이벤트도 처리합니다.이것이 매핑 응용프로그램이 처리하는 방식입니다.

자세한 내용은 다음과 같습니다.

let element = document.getElementById('el');
let scale = 1.0;
element.addEventListener('wheel', (ev) => {
  // This is crucial. Without it, the browser will do a full page zoom
  ev.preventDefault();

  // This is an empirically determined heuristic.
  // Unfortunately I don't know of any way to do this better.
  // Typical deltaY values from a trackpad pinch are under 1.0
  // Typical deltaY values from a mouse wheel are more than 100.
  let isPinch = Math.abs(ev.deltaY) < 50;

  if (isPinch) {
    // This is a pinch on a trackpad
    let factor = 1 - 0.01 * ev.deltaY;
    scale *= factor;
    element.innerText = `Pinch: scale is ${scale}`;
  } else {
    // This is a mouse wheel
    let strength = 1.4;
    let factor = ev.deltaY < 0 ? strength : 1.0 / strength;
    scale *= factor;
    element.innerText = `Mouse: scale is ${scale}`;
  }
});
<div id='el' style='width:400px; height:300px; background:#ffa'>
  Scale: 1.0
</div>

이 답들 중 어느 것도 제가 찾던 것을 이루지 못했기 때문에, 결국 제가 직접 무언가를 쓰게 되었습니다.MacBookPro 트랙패드를 사용하여 웹 사이트의 이미지를 핀치 확대/축소하려고 합니다.(jQuery가 필요한) 다음 코드는 적어도 크롬과 엣지에서 작동하는 것 같습니다.아마도 이것은 다른 사람에게 도움이 될 것입니다.

function setupImageEnlargement(el)
{
    // "el" represents the image element, such as the results of document.getElementByd('image-id')
    var img = $(el);
    $(window, 'html', 'body').bind('scroll touchmove mousewheel', function(e)
    {
        //TODO: need to limit this to when the mouse is over the image in question

        //TODO: behavior not the same in Safari and FF, but seems to work in Edge and Chrome

        if (typeof e.originalEvent != 'undefined' && e.originalEvent != null
            && e.originalEvent.wheelDelta != 'undefined' && e.originalEvent.wheelDelta != null)
        {
            e.preventDefault();
            e.stopPropagation();
            console.log(e);
            if (e.originalEvent.wheelDelta > 0)
            {
                // zooming
                var newW = 1.1 * parseFloat(img.width());
                var newH = 1.1 * parseFloat(img.height());
                if (newW < el.naturalWidth && newH < el.naturalHeight)
                {
                    // Go ahead and zoom the image
                    //console.log('zooming the image');
                    img.css(
                    {
                        "width": newW + 'px',
                        "height": newH + 'px',
                        "max-width": newW + 'px',
                        "max-height": newH + 'px'
                    });
                }
                else
                {
                    // Make image as big as it gets
                    //console.log('making it as big as it gets');
                    img.css(
                    {
                        "width": el.naturalWidth + 'px',
                        "height": el.naturalHeight + 'px',
                        "max-width": el.naturalWidth + 'px',
                        "max-height": el.naturalHeight + 'px'
                    });
                }
            }
            else if (e.originalEvent.wheelDelta < 0)
            {
                // shrinking
                var newW = 0.9 * parseFloat(img.width());
                var newH = 0.9 * parseFloat(img.height());

                //TODO: I had added these data-attributes to the image onload.
                // They represent the original width and height of the image on the screen.
                // If your image is normally 100% width, you may need to change these values on resize.
                var origW = parseFloat(img.attr('data-startwidth'));
                var origH = parseFloat(img.attr('data-startheight'));

                if (newW > origW && newH > origH)
                {
                    // Go ahead and shrink the image
                    //console.log('shrinking the image');
                    img.css(
                    {
                        "width": newW + 'px',
                        "height": newH + 'px',
                        "max-width": newW + 'px',
                        "max-height": newH + 'px'
                    });
                }
                else
                {
                    // Make image as small as it gets
                    //console.log('making it as small as it gets');
                    // This restores the image to its original size. You may want
                    //to do this differently, like by removing the css instead of defining it.
                    img.css(
                    {
                        "width": origW + 'px',
                        "height": origH + 'px',
                        "max-width": origW + 'px',
                        "max-height": origH + 'px'
                    });
                }
            }
        }
    });
}

제 대답은 제프리의 대답에서 영감을 받았습니다.그 대답이 보다 추상적인 해결책을 제공하는 경우, 저는 잠재적으로 구현하는 방법에 대한 보다 구체적인 단계를 제공하려고 노력합니다.이는 단순한 가이드로, 보다 우아하게 구현할 수 있습니다.자세한 예는 MDN 웹 문서별 튜토리얼을 참조하십시오.

HTML:

<div id="zoom_here">....</div>

제이에스

<script>
var dist1=0;
function start(ev) {
           if (ev.targetTouches.length == 2) {//check if two fingers touched screen
               dist1 = Math.hypot( //get rough estimate of distance between two fingers
                ev.touches[0].pageX - ev.touches[1].pageX,
                ev.touches[0].pageY - ev.touches[1].pageY);                  
           }
    
    }
    function move(ev) {
           if (ev.targetTouches.length == 2 && ev.changedTouches.length == 2) {
                 // Check if the two target touches are the same ones that started
               var dist2 = Math.hypot(//get rough estimate of new distance between fingers
                ev.touches[0].pageX - ev.touches[1].pageX,
                ev.touches[0].pageY - ev.touches[1].pageY);
                //alert(dist);
                if(dist1>dist2) {//if fingers are closer now than when they first touched screen, they are pinching
                  alert('zoom out');
                }
                if(dist1<dist2) {//if fingers are further apart than when they first touched the screen, they are making the zoomin gesture
                   alert('zoom in');
                }
           }
           
    }
        document.getElementById ('zoom_here').addEventListener ('touchstart', start, false);
        document.getElementById('zoom_here').addEventListener('touchmove', move, false);
</script>

이는 제프리 스위니가 언급한 것과 같습니다. 수업에서 구현하는 방법에 대한 전체 예입니다.

this.touch.isPinch = false;
this.touc.pinchStart = 0;

this.touch.onTouchStart = (e) => {
   if (e.touches.length === 2) {
    this.touch.pinchStart = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY);
    this.touch.isScaling = true;
  }
}

this.touch.onTouchMove = (e) => {
    if (this.touch.isScaling) {
      const distance = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY);

      if (this.touch.pinchStart >= 200 && distance <= 90) this.touchPichOut(); //call function for pinchOut
      if (this.touch.pinchStart <= 100 && distance >= 280) this.touchPichIn(); //call function for pinchIn
    }
}

this.touch.onTouchCancel = (e) => {
   this.touch.isScaling = false;
}

this.touch.onTouchEnd = (e) => {
  if (this.touch.isScaling) this.touch.isScaling = false;
}

안부 전해요

언급URL : https://stackoverflow.com/questions/11183174/simplest-way-to-detect-a-pinch

반응형