pixi-viewport icon indicating copy to clipboard operation
pixi-viewport copied to clipboard

trackpads - how to have pinch do zoom and two finger movement pan the viewport?

Open dontwork opened this issue 5 years ago • 25 comments

dontwork avatar Jun 22 '19 15:06 dontwork

Is this for Mac or PC trackpads? Have you tried viewport.wheel() for the zoom? (I expect it won't work but worth a try.)

davidfig avatar Jun 23 '19 06:06 davidfig

this makes it so that 2 finger dragging zooms, overriding the previous behaviour of 2 finger dragging moving the camera

is it possible for 2 finger drag to move the camera and pinching do the zoom

dontwork avatar Jun 23 '19 08:06 dontwork

It is possible. I don’t think it’s currently supported. I’ll see if I can get it working.

davidfig avatar Jun 23 '19 13:06 davidfig

@davidfig any thoughts on this one?

dontwork avatar Jun 30 '19 11:06 dontwork

Still working on this. I've had limited success using https://medium.com/@auchenberg/detecting-multi-touch-trackpad-gestures-in-javascript-a2505babb10e

To give you an idea where I am: it sort of works on PC trackpads but the 'wheel' event (on my device) locks the direction--i.e., if you start a horizontal two-finger drag (without press), then it will not return a event.deltaY and vice versa. If you start a two-finger drag with a diagonal move then it works correctly.

Sigh. Still working through this last blocking PC issue. I also need to implement gestureevents to support Safari.

davidfig avatar Jun 30 '19 12:06 davidfig

This may not be possible. Here's the stackoverflow conversation: https://stackoverflow.com/questions/56825793/javascript-wheel-event-locks-to-horizontal-or-vertical-movement-and-does-not-all

I'll see if there are any other suggestions, but on Chrome/PC, the trackpad will not properly register the movement events. Firefox is generally okay support (although the scaling for the movement is weird). Safari would require a different API (GestureEvents).

davidfig avatar Jul 01 '19 12:07 davidfig

And here's the chrome bug report: https://bugs.chromium.org/p/chromium/issues/detail?id=980479

Feel free to star the report if you're interested in having this feature.

davidfig avatar Jul 07 '19 14:07 davidfig

Looks like chrome is not going to support this behavior. I'm going to close this issue since it's not worth implementing if it doesn't work in chrome.

davidfig avatar Jul 09 '19 19:07 davidfig

I am not sure i understand the relevance of the chrome issues you cite to the original intention behind this ticket.

To be clear, does the behaviour in chrome prevent pinch zooming altogether?

dontwork avatar Jul 15 '19 13:07 dontwork

Correct. On chrome you cannot use two-finger movement on a trackpad. Once you start a two-finger movement, chrome locks you in the horizontal or vertical direction. You do not get event data about the other axis. Zoom may work but you can't perform the same two-finger move and zoom that currently works on touchscreens.

I see no way around this limitation and chromium doesn't want to change the behavior. I'm open to alternative suggestions.

davidfig avatar Jul 15 '19 13:07 davidfig

I'm not sure but i know figma (also uses webgl) have pinch to zoom, as mentioned here: https://medium.com/@auchenberg/detecting-multi-touch-trackpad-gestures-in-javascript-a2505babb10e

dontwork avatar Jul 22 '19 10:07 dontwork

Hi @davidfig , I'm also need a 'pinch to zoom' and 'two-fingers drag' the workaround posted by @dontwork could be used in pixi-viewport?

ygorlf avatar Mar 05 '20 20:03 ygorlf

Yes, I've been working on a patch to support both PC and Mac trackpads for wheel scroll, and pinch and zoom. It's currently in the gesture branch of this repository. I think the PC code is working, but I still need to add the code for mac (it uses a proprietary gesture library).

It's on my list, but I probably won't get a chance to finish it for a few weeks.

davidfig avatar Mar 06 '20 00:03 davidfig

Ok, I'll test the gesture branch and track the status of the feature. Thank you so much, your library is helping me a lot, thanks for put the time to create this. :)

ygorlf avatar Mar 06 '20 03:03 ygorlf

Cool. let me know how the branch works and if you find any bugs. i've tested it somewhat and it seems to work. i do need to get the mac gesture stuff working for my current project, so it's a high priority on my list.

davidfig avatar Mar 06 '20 04:03 davidfig

Hi Any progress on this?

crutch12 avatar Apr 30 '20 20:04 crutch12

We're also in need of this feature.

@davidfig were you able to get the Mac code added? Happy to test the gesture branch if so.

(This library is great btw!) Thanks!

npgauth avatar May 11 '20 16:05 npgauth

I have not, but I really need to get that done. I don't have my mac with me today, but I'll put it in my bag for tomorrow and get this sorted out. I'd love to take it off my list as well. Stay tuned.

davidfig avatar May 12 '20 04:05 davidfig

Curious how this is going.

I made a poor mans version which works on chrome but not properly safari.

Here is the code for the plugin

import { Plugin, Viewport } from "pixi-viewport";
import { assign } from "lodash";

type Options = {
    moveSpeed: number;
    moveReverse: boolean;
    zoomSpeed: number;
    zoomReverse: boolean;
};

const defaults: Options = {
    moveSpeed: 1,
    moveReverse: false,
    zoomSpeed: 1,
    zoomReverse: false,
};

export class PinchToZoomAndMove extends Plugin {
    private parent: Viewport;
    private options: Options;
    private moveReverse: number;
    private zoomReverse: number;

    constructor(parent: Viewport, options: Partial<Options>) {
        super(parent);
        this.parent = parent;
        this.options = assign({}, options, defaults);

        this.moveReverse = options.moveReverse ? 1 : -1;
        this.zoomReverse = options.zoomReverse ? 1 : -1;
    }

    wheel(event: WheelEvent) {
        if (event.ctrlKey) {
            this.zoom(event);
        } else {
            this.pan(event);
        }
    }

    private pan(event: WheelEvent) {
        this.parent.x +=
            event.deltaX * this.options.moveSpeed * this.moveReverse;
        this.parent.y +=
            event.deltaY * this.options.moveSpeed * this.moveReverse;
    }

    private zoom(event: WheelEvent) {
        const delta =
            1 -
            (this.zoomReverse * event.deltaY * this.options.zoomSpeed) / 300;

        // hack as input is not typed on parent
        const point = (this.parent as any).input.getPointerPosition(event);
        const oldPoint = this.parent.toLocal(point);

        this.parent.scale.x *= delta;
        this.parent.scale.y *= delta;

        const newPoint = this.parent.toGlobal(oldPoint);
        this.parent.x += point.x - newPoint.x;
        this.parent.y += point.y - newPoint.y;
    }
}

Here is how to use it

viewport.plugins.add("wheel", new PinchToZoomAndMove(viewport, {}));

Also on mac (not sure on windows) if you pinch you zoom into the page, to prevent this I have used

window.addEventListener(
    "mousewheel",
    (e: Event) => {
        e.preventDefault();
    },
    { passive: false }
);

I will test on windows soon but hoping this patch in here will solve all these problems

jkar32 avatar May 28 '20 03:05 jkar32

I got about halfway done with it, and then the project I was consulting on ended. I definitely want to finish this, but it may not be until my schedule opens up a bit.

davidfig avatar Jul 03 '20 23:07 davidfig

Hi Has this issue been fixed in the latest version? it doesn't seem to work on mac/chrome. or need some special configuration?

mjzzz1 avatar Mar 29 '22 02:03 mjzzz1

This is my setup. With a trackpad it allows to do 2-finger pan and pinch for zoom. For mouse it allows to do middle, right click pan and ctrl+wheel to zoom.

// configure viewport
viewport.current
  .drag({
    clampWheel: false,
    mouseButtons: 'middle-right',
  })
  .pinch()
  .wheel({ smooth: 3, trackpadPinch: true, wheelZoom: false })
  .decelerate({
    friction: 0.8,
  })
  .clampZoom({
    minScale: 0.05,
    maxScale: 4,
  });

However I would like to have a similar behaviour as Miro's "Auto-switch". Somehow they detect if a trackpad or a mouse is used and switch to wheel(wheelZoom: true) when using a mouse. At least this is how I believe it works. Anyone know how to achieve that?

fakob avatar Apr 02 '22 15:04 fakob

For anyone interested, I did a "gesture map" where I looked at the behaviour of using mouse/trackpad in different applications.

Research - flow based frameworks - Gesture map

fakob avatar Apr 02 '22 15:04 fakob

Regarding Miro's auto-switch behaviour I found this snippet on stackoverflow which allows for differentiating between a device with a scroll-wheel and trackpad. I tested it with some trackpads and mouses on mac and pc and it seems to work fine.

function detectTrackPad(e) {
  var isTrackpad = false;
  if (e.wheelDeltaY) {
    if (e.wheelDeltaY === (e.deltaY * -3)) {
      isTrackpad = true;
    }
  }
  else if (e.deltaMode === 0) {
    isTrackpad = true;
  }
  console.log(isTrackpad ? "Trackpad detected" : "Mousewheel detected");
}

document.addEventListener("mousewheel", detectTrackPad, false);
document.addEventListener("DOMMouseScroll", detectTrackPad, false);

And based on this detection I am setting wheelZoom to true for scroll-wheels or false for trackpads. See here: https://github.com/fakob/plug-and-play/pull/91/files

@davidfig, you have created an awesome library. Thanks for your work!

fakob avatar Apr 03 '22 10:04 fakob

I have a follow up question to this wheelZoom setup. When it is set to false I can zoom via Ctrl+Scroll.

Is there any way to also allow Cmd+Scroll to be used when on a Mac?

fakob avatar Oct 27 '23 16:10 fakob