davidfig / pixi-viewport

A highly configurable viewport/2D camera designed to work with pixi.js
https://davidfig.github.io/pixi-viewport/
MIT License
1.06k stars 176 forks source link

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

Open dontwork opened 5 years ago

davidfig commented 5 years ago

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.)

dontwork commented 5 years ago

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

davidfig commented 5 years ago

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

dontwork commented 5 years ago

@davidfig any thoughts on this one?

davidfig commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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.

dontwork commented 5 years ago

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?

davidfig commented 5 years ago

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.

dontwork commented 5 years ago

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

ygorlf commented 4 years ago

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?

davidfig commented 4 years ago

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.

ygorlf commented 4 years ago

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. :)

davidfig commented 4 years ago

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.

crutch12 commented 4 years ago

Hi Any progress on this?

npgauth commented 4 years ago

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!

davidfig commented 4 years ago

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.

jkar32 commented 4 years ago

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

davidfig commented 4 years ago

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.

mjzzz1 commented 2 years ago

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

fakob commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

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?

hevans90 commented 2 weeks ago

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

Thank you for this, this was extremely helpful to me.

hevans90 commented 2 weeks ago

Also @fakob here's how to get your nice setup working with the cmd (meta) keys on mac:

image
fakob commented 1 week ago

@hevans90 I am glad the gesture map was useful to you and thanks for your cmd key fix. That is excellent! I will try this out soon.