Поймать pinch-zoom в браузере

#html #touch #gesture #pinchzoom

#HTML #коснитесь #жест #pinchzoom

Вопрос:

У меня есть веб-приложение, которое по сути является холстом, на котором вы можете рисовать. Я обрабатываю рисунок — либо мышью, либо одним касанием пальца — и он работает хорошо.

Холст больше экрана, и мне нужно реализовать свой собственный механизм масштабирования (потому что я хочу увеличить только холст, а не весь экран). Я добавил обработчик к wheel событию, и я правильно обрабатываю элементы управления. Теперь мне нужно обработать пинч-зумы.

Мой холст как track-action: pinch-zoom настройки CSS. Это позволяет выполнять прокрутку двумя движениями пальца, что превосходно. Я хочу, чтобы браузер тоже обрабатывал пинч-масштабирование, но я хочу сам управлять логикой масштабирования (как я делаю с колесиком мыши).

Есть ли какой-либо способ перехватить событие pinch-zoom и переопределить поведение масштабирования?

Я использую Chrome на Android, но этот метод также должен работать с Safari на iOS.

Комментарии:

1. Я уже реализовал алгоритм пинч-зума двумя пальцами с масштабированием в точке для холста, но я использую touch-action: manipulation . Если вы сможете справиться с этой настройкой CSS, я мог бы опубликовать некоторый код.

2. Нет, я не могу, у меня не может быть pan-x pan-y

3. я хочу сделать обратное — позволить браузеру обрабатывать масштабирование отдельных элементов. вы подразумеваете, что есть способ сделать это?

Ответ №1:

кстати, хорошая идея. я нашел кое-что, на codepen стоит потратить время. также я немного урезал его и вставил в виде фрагмента ниже. дайте мне знать, если это вам поможет. кроме того, если вы хотите использовать библиотеку, вы можете попробовать hammer.js или jgestures для жестов пинч-масштабирования.

   var image_x = 0, image_y = 0;
  var zoom = 0.5;
  var mouse_x = 0, mouse_y = 0, finger_dist = 0;
  var source_image_obj = new Image();
  source_image_obj.addEventListener('load', function () {
    reset_settings();
  }, false); // Reset (x,y,zoom) when new image loads

  function load_url() {
    source_image_obj.src = document.getElementById("theurl").value; // load the image
  }

  function update_canvas() {
    var mainCanvas = document.getElementById("mainCanvas");
    var mainCanvasCTX = document.getElementById("mainCanvas").getContext("2d");
    var canvas_w = mainCanvas.width, canvas_h = mainCanvas.height; // make things easier to read below
    // Keep picture in bounds
    if (image_x - (canvas_w * zoom / 2) > source_image_obj.width) image_x = source_image_obj.width   (canvas_w * zoom / 2);
    if (image_y - (canvas_h * zoom / 2) > source_image_obj.height) image_y = source_image_obj.height   (canvas_h * zoom / 2);
    if (image_x   (canvas_w * zoom / 2) < 0) image_x = 0 - (canvas_w * zoom / 2);
    if (image_y   (canvas_h * zoom / 2) < 0) image_y = 0 - (canvas_h * zoom / 2);
    // Draw the scaled image onto the canvas
    mainCanvasCTX.clearRect(0, 0, canvas_w, canvas_h);
    mainCanvasCTX.drawImage(source_image_obj, image_x - (canvas_w * zoom / 2), image_y - (canvas_h * zoom / 2), canvas_w * zoom, canvas_h * zoom, 0, 0, canvas_w, canvas_h);
  }

  function reset_settings() {
    image_x = source_image_obj.width / 2;
    image_y = source_image_obj.height / 2;
    zoom = 1;
    update_canvas(); // Draw the image in its new position
  }

  document.addEventListener('wheel', function (e) {
    if (e.deltaY < 0) {
      zoom = zoom * 1.5;
    } else {
      zoom = zoom / 1.5;
    }
    update_canvas();
  }, false);

  document.addEventListener('mousemove', function (e) {
    if (e.buttons > 0) {
      window.getSelection().empty();
      image_x = image_x   zoom * (mouse_x - e.clientX);
      image_y = image_y   zoom * (mouse_y - e.clientY);
    }
    mouse_x = e.clientX;
    mouse_y = e.clientY; // Save for next time
    update_canvas(); // draw the image in its new position
  }, false);

  function get_distance(e) {
    var diffX = e.touches[0].clientX - e.touches[1].clientX;
    var diffY = e.touches[0].clientY - e.touches[1].clientY;
    return Math.sqrt(diffX * diffX   diffY * diffY); // Pythagorean theorem
  }

  document.addEventListener('touchstart', function (e) {
    if (e.touches.length > 1) { // if multiple touches (pinch zooming)
      finger_dist = get_distance(e); // Save current finger distance
    } // Else just moving around
    mouse_x = e.touches[0].clientX; // Save finger position
    mouse_y = e.touches[0].clientY; //
  }, false);

  document.addEventListener('touchmove', function (e) {
    e.preventDefault(); // Stop the window from moving
    if (e.touches.length > 1) { // If pinch-zooming
      var new_finger_dist = get_distance(e); // Get current distance between fingers
      zoom = zoom * Math.abs(finger_dist / new_finger_dist); // Zoom is proportional to change
      finger_dist = new_finger_dist; // Save current distance for next time
    } else { // Else just moving around
      image_x = image_x   (zoom * (mouse_x - e.touches[0].clientX)); // Move the image
      image_y = image_y   (zoom * (mouse_y - e.touches[0].clientY)); //
      mouse_x = e.touches[0].clientX; // Save finger position for next time
      mouse_y = e.touches[0].clientY; //
    }
    update_canvas(); // draw the new position
  }, false);

  document.addEventListener('touchend', function (e) {
    mouse_x = e.touches[0].clientX;
    mouse_y = e.touches[0].clientY; // could be down to 1 finger, back to moving image
  }, false);  
     * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    canvas {
      background: #e74c3c;
      border: 4px solid black;
    }
    .box-photo {
      border: 1px dashed black;
    }
    .box-photo img {
      width: 100%;
    }  
 <html>
<head>
  <meta charset="utf-8" />
<body onload="load_url();">
  <div class="box">
    <div class="box-photo">
      <canvas id="mainCanvas" width="500" height="600">
        <input id="theurl" value="https://mlb-s1-p.mlstatic.com/relogio-mondaine-classico-78527-original-a-prova-dagua-202101-MLB20273713546_042015-F.jpg">
        Your browser does not support the HTML5 canvas tag.
      </canvas>
    </div>
  </div>
</body>
</html>