Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture pinch-zoom gestures from the trackpad in a desktop browser (and prevent default)?

Tags:

javascript

If you open Google Maps in Chrome/Firefox on a laptop with a trackpad, if you pinch-zoom, it just zooms the map, and the floating UI elements remain static. So I know what I am trying to do is possible.

It seems the browser doesn't emit touch* events for trackpad touches on desktop browsers, but it does emit a series of wheel events (with event.ctrlKey set to true) for a trackpad pinch-zoom gesture.

The problem is, even with event.preventDefault(), the browser still always zooms the whole page. It seems that calling preventDefault() on a wheel event just prints this warning in the console (Chrome 92):

[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312`

(The URL in the warning doesn't seem to be any use.)

I tried using same the meta viewport tag as Google Maps (<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">) but it doesn't help.

So how does Google Maps do it? How do they prevent the default behaviour (zooming the whole page) when you pinch-zoom on the trackpad?

like image 740
callum Avatar asked Aug 16 '21 19:08

callum


People also ask

How do I pinch zoom in Chrome?

Tip: On your touchscreen, you can touch and hold an area with 2 fingers, and then pinch open to zoom in, or pinch close to zoom out.

How do you pinch 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.

How do you pinch zoom without a mouse pad?

ctrl + mousewheel will then control the pinch zoom instead of the regular zoom.

How do you pinch zoom on Android?

Tap anywhere on the screen, except the keyboard or navigation bar. Drag 2 fingers to move around the screen. Pinch with 2 fingers to adjust zoom. To stop magnification, use your magnification shortcut again.


1 Answers

I don't have a trackpad at hand, but since you said that wheel events were emmited, I assume the context is the same by using a mouse's wheel.

TL; DR

Calling addEventListener() with {passive: false} as its third argument will do it.

Namely:

window.addEventListener('wheel', function(e) {

  e.preventDefault()
  ...

}, {passive: false})

Explanation

In addEventListener()'s document, the description of the passive option states that:

A boolean value that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning.

And according to the section titled "Improving scrolling performance with passive listeners" in the same page:

According to the specification, the default value for the passive option is always false. However, this introduces the potential for event listeners handling certain touch events (among others) to block the browser's main thread while it is attempting to handle scrolling, resulting in possibly enormous reduction in performance during scroll handling.

To prevent this problem, some browsers (specifically, Chrome and Firefox) have changed the default value of the passive option to true for the touchstart and touchmove events on the document-level nodes Window, Document, and Document.body. This prevents the event listener from being called, so it can't block page rendering while the user is scrolling.

Although the paragraph above only mentions touchstart and touchmove events, I found that it is also applied to the wheel event in Chrome and Firefox.

So if you want to make preventDefault() work, you have to specifically set the passive option to false.

like image 152
Microloft Avatar answered Oct 28 '22 10:10

Microloft