Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch pinch-zoom in browser

I have a web application that is basically a canvas you can draw on. I'm handling the drawing - either by mouse or by single finger touch - and it's working well.

The canvas is larger than the screen, and I need to implement my own zooming mechanism (because I only want to zoom the canvas, not the entire screen). I've added a handler to the wheel event, and I process Control-Wheels properly. Now I need to handle pinch-zooms.

My canvas as a track-action: pinch-zoom CSS settings. This enables two finger swipes for scrolling, which is excellent. I want to let the browser handle pinch-zooms, too, but I want to handle the zooming logic myself (like I do with the mouse wheel).

Is there any way to catch the pinch-zoom event and override the zooming behavior?

I'm using Chrome on Android, but this technique should also work with Safari on iOS.

like image 521
zmbq Avatar asked Mar 07 '19 11:03

zmbq


People also ask

How do I simulate pinch zoom in Chrome?

Hold down Shift then click and move your mouse to emulate pinch zooming.

How do you pinch a browser?

x.x, you can pinch zoom pressing 'Toggle Device toolbar' at dev tools and after hold SHIFT and click-drag your mouse. Save this answer.

How do I turn off pinch zoom in Chrome?

Navigate to the URL chrome://flags/#enable-pinch in your browser and disable the feature.

How do I pinch my screen to zoom?

Pinch to zoom in on content: In full screen mode, touch the video with two fingers. Move your fingers away from one another, while touching the video screen. Once you let go, the video will play at the new zoom level.


1 Answers

nice idea btw. i found something worth your time on codepen. also i stripped it down a little and inserted as snippet below. let me know if it helps you. additionally if you want to use library, you can try hammer.js or jgestures for pinch zooming gestures.

  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>
like image 113
Galzor Avatar answered Sep 22 '22 12:09

Galzor